android_hardware_camera2_DngCreator.cpp revision b6079005ed0631c3972ff427f56e12523ec214a7
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 "android_runtime/AndroidRuntime.h" 35#include "android_runtime/android_hardware_camera2_CameraMetadata.h" 36 37#include <jni.h> 38#include <JNIHelp.h> 39 40using namespace android; 41using namespace img_utils; 42 43#define BAIL_IF_INVALID(expr, jnienv, tagId) \ 44 if ((expr) != OK) { \ 45 jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 46 "Invalid metadata for tag %x", tagId); \ 47 return; \ 48 } 49 50#define BAIL_IF_EMPTY(entry, jnienv, tagId) \ 51 if (entry.count == 0) { \ 52 jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \ 53 "Missing metadata fields for tag %x", tagId); \ 54 return; \ 55 } 56 57#define ANDROID_DNGCREATOR_CTX_JNI_ID "mNativeContext" 58 59static struct { 60 jfieldID mNativeContext; 61} gDngCreatorClassInfo; 62 63static struct { 64 jmethodID mWriteMethod; 65} gOutputStreamClassInfo; 66 67enum { 68 BITS_PER_SAMPLE = 16, 69 BYTES_PER_SAMPLE = 2, 70 TIFF_IFD_0 = 0 71}; 72 73// ---------------------------------------------------------------------------- 74 75// This class is not intended to be used across JNI calls. 76class JniOutputStream : public Output, public LightRefBase<JniOutputStream> { 77public: 78 JniOutputStream(JNIEnv* env, jobject outStream); 79 80 virtual ~JniOutputStream(); 81 82 status_t open(); 83 status_t write(const uint8_t* buf, size_t offset, size_t count); 84 status_t close(); 85private: 86 enum { 87 BYTE_ARRAY_LENGTH = 1024 88 }; 89 jobject mOutputStream; 90 JNIEnv* mEnv; 91 jbyteArray mByteArray; 92}; 93 94JniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream), 95 mEnv(env) { 96 mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH); 97 if (mByteArray == NULL) { 98 jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array."); 99 } 100} 101 102JniOutputStream::~JniOutputStream() { 103 mEnv->DeleteLocalRef(mByteArray); 104} 105 106status_t JniOutputStream::open() { 107 // Do nothing 108 return OK; 109} 110 111status_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) { 112 while(count > 0) { 113 size_t len = BYTE_ARRAY_LENGTH; 114 len = (count > len) ? len : count; 115 mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset)); 116 117 if (mEnv->ExceptionCheck()) { 118 return BAD_VALUE; 119 } 120 121 mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray, 122 0, len); 123 124 if (mEnv->ExceptionCheck()) { 125 return BAD_VALUE; 126 } 127 128 count -= len; 129 offset += len; 130 } 131 return OK; 132} 133 134status_t JniOutputStream::close() { 135 // Do nothing 136 return OK; 137} 138 139// ---------------------------------------------------------------------------- 140 141extern "C" { 142 143static TiffWriter* DngCreator_getCreator(JNIEnv* env, jobject thiz) { 144 ALOGV("%s:", __FUNCTION__); 145 return reinterpret_cast<TiffWriter*>(env->GetLongField(thiz, 146 gDngCreatorClassInfo.mNativeContext)); 147} 148 149static void DngCreator_setCreator(JNIEnv* env, jobject thiz, sp<TiffWriter> writer) { 150 ALOGV("%s:", __FUNCTION__); 151 TiffWriter* current = DngCreator_getCreator(env, thiz); 152 if (writer != NULL) { 153 writer->incStrong((void*) DngCreator_setCreator); 154 } 155 if (current) { 156 current->decStrong((void*) DngCreator_setCreator); 157 } 158 env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext, 159 reinterpret_cast<jlong>(writer.get())); 160} 161 162static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) { 163 ALOGV("%s:", __FUNCTION__); 164 165 gDngCreatorClassInfo.mNativeContext = env->GetFieldID(clazz, 166 ANDROID_DNGCREATOR_CTX_JNI_ID, "J"); 167 LOG_ALWAYS_FATAL_IF(gDngCreatorClassInfo.mNativeContext == NULL, 168 "can't find android/hardware/camera2/DngCreator.%s", 169 ANDROID_DNGCREATOR_CTX_JNI_ID); 170 171 jclass outputStreamClazz = env->FindClass("java/io/OutputStream"); 172 LOG_ALWAYS_FATAL_IF(outputStreamClazz == NULL, "Can't find java/io/OutputStream class"); 173 gOutputStreamClassInfo.mWriteMethod = env->GetMethodID(outputStreamClazz, "write", "([BII)V"); 174 LOG_ALWAYS_FATAL_IF(gOutputStreamClassInfo.mWriteMethod == NULL, "Can't find write method"); 175} 176 177static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr, 178 jobject resultsPtr) { 179 ALOGV("%s:", __FUNCTION__); 180 CameraMetadata characteristics; 181 CameraMetadata results; 182 if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) { 183 jniThrowException(env, "java/lang/AssertionError", 184 "No native metadata defined for camera characteristics."); 185 return; 186 } 187 if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) { 188 jniThrowException(env, "java/lang/AssertionError", 189 "No native metadata defined for capture results."); 190 return; 191 } 192 193 sp<TiffWriter> writer = new TiffWriter(); 194 195 writer->addIfd(TIFF_IFD_0); 196 197 status_t err = OK; 198 199 const uint32_t samplesPerPixel = 1; 200 const uint32_t bitsPerSample = BITS_PER_SAMPLE; 201 const uint32_t bitsPerByte = BITS_PER_SAMPLE / BYTES_PER_SAMPLE; 202 uint32_t imageWidth = 0; 203 uint32_t imageHeight = 0; 204 205 OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB; 206 207 // TODO: Greensplit. 208 // TODO: UniqueCameraModel 209 // TODO: Add remaining non-essential tags 210 { 211 // Set orientation 212 uint16_t orientation = 1; // Normal 213 BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env, 214 TAG_ORIENTATION); 215 } 216 217 { 218 // Set subfiletype 219 uint32_t subfileType = 0; // Main image 220 BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env, 221 TAG_NEWSUBFILETYPE); 222 } 223 224 { 225 // Set bits per sample 226 uint16_t bits = static_cast<uint16_t>(bitsPerSample); 227 BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env, 228 TAG_BITSPERSAMPLE); 229 } 230 231 { 232 // Set compression 233 uint16_t compression = 1; // None 234 BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env, 235 TAG_COMPRESSION); 236 } 237 238 { 239 // Set dimensions 240 camera_metadata_entry entry = 241 characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE); 242 BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH); 243 uint32_t width = static_cast<uint32_t>(entry.data.i32[2]); 244 uint32_t height = static_cast<uint32_t>(entry.data.i32[3]); 245 BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &width, TIFF_IFD_0), env, 246 TAG_IMAGEWIDTH); 247 BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &height, TIFF_IFD_0), env, 248 TAG_IMAGELENGTH); 249 imageWidth = width; 250 imageHeight = height; 251 } 252 253 { 254 // Set photometric interpretation 255 uint16_t interpretation = 32803; 256 BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation, 257 TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION); 258 } 259 260 { 261 // Set blacklevel tags 262 camera_metadata_entry entry = 263 characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN); 264 BAIL_IF_EMPTY(entry, env, TAG_BLACKLEVEL); 265 const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32); 266 BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, TIFF_IFD_0), env, 267 TAG_BLACKLEVEL); 268 269 uint16_t repeatDim[2] = {2, 2}; 270 BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, TIFF_IFD_0), env, 271 TAG_BLACKLEVELREPEATDIM); 272 } 273 274 { 275 // Set samples per pixel 276 uint16_t samples = static_cast<uint16_t>(samplesPerPixel); 277 BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0), 278 env, TAG_SAMPLESPERPIXEL); 279 } 280 281 { 282 // Set planar configuration 283 uint16_t config = 1; // Chunky 284 BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0), 285 env, TAG_PLANARCONFIGURATION); 286 } 287 288 { 289 // Set CFA pattern dimensions 290 uint16_t repeatDim[2] = {2, 2}; 291 BAIL_IF_INVALID(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, TIFF_IFD_0), 292 env, TAG_CFAREPEATPATTERNDIM); 293 } 294 295 { 296 // Set CFA pattern 297 camera_metadata_entry entry = 298 characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT); 299 BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN); 300 camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa = 301 static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>( 302 entry.data.u8[0]); 303 switch(cfa) { 304 case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: { 305 uint8_t cfa[4] = {0, 1, 1, 2}; 306 BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0), 307 env, TAG_CFAPATTERN); 308 opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB; 309 break; 310 } 311 case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: { 312 uint8_t cfa[4] = {1, 0, 2, 1}; 313 BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0), 314 env, TAG_CFAPATTERN); 315 opcodeCfaLayout = OpcodeListBuilder::CFA_GRBG; 316 break; 317 } 318 case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: { 319 uint8_t cfa[4] = {1, 2, 0, 1}; 320 BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0), 321 env, TAG_CFAPATTERN); 322 opcodeCfaLayout = OpcodeListBuilder::CFA_GBRG; 323 break; 324 } 325 case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: { 326 uint8_t cfa[4] = {2, 1, 1, 0}; 327 BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0), 328 env, TAG_CFAPATTERN); 329 opcodeCfaLayout = OpcodeListBuilder::CFA_BGGR; 330 break; 331 } 332 default: { 333 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 334 "Invalid metadata for tag %d", TAG_CFAPATTERN); 335 return; 336 } 337 } 338 } 339 340 { 341 // Set CFA plane color 342 uint8_t cfaPlaneColor[3] = {0, 1, 2}; 343 BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0), 344 env, TAG_CFAPLANECOLOR); 345 } 346 347 { 348 // Set CFA layout 349 uint16_t cfaLayout = 1; 350 BAIL_IF_INVALID(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0), 351 env, TAG_CFALAYOUT); 352 } 353 354 { 355 // Set DNG version information 356 uint8_t version[4] = {1, 4, 0, 0}; 357 BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0), 358 env, TAG_DNGVERSION); 359 360 uint8_t backwardVersion[4] = {1, 1, 0, 0}; 361 BAIL_IF_INVALID(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, TIFF_IFD_0), 362 env, TAG_DNGBACKWARDVERSION); 363 } 364 365 { 366 // Set whitelevel 367 camera_metadata_entry entry = 368 characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL); 369 BAIL_IF_EMPTY(entry, env, TAG_WHITELEVEL); 370 uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]); 371 BAIL_IF_INVALID(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), env, 372 TAG_WHITELEVEL); 373 } 374 375 { 376 // Set default scale 377 uint32_t defaultScale[4] = {1, 1, 1, 1}; 378 BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, TIFF_IFD_0), 379 env, TAG_DEFAULTSCALE); 380 } 381 382 bool singleIlluminant = false; 383 { 384 // Set calibration illuminants 385 camera_metadata_entry entry1 = 386 characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1); 387 BAIL_IF_EMPTY(entry1, env, TAG_CALIBRATIONILLUMINANT1); 388 camera_metadata_entry entry2 = 389 characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2); 390 if (entry2.count == 0) { 391 singleIlluminant = true; 392 } 393 uint16_t ref1 = entry1.data.u8[0]; 394 395 BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1, 396 TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1); 397 398 if (!singleIlluminant) { 399 uint16_t ref2 = entry2.data.u8[0]; 400 BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2, 401 TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2); 402 } 403 } 404 405 { 406 // Set color transforms 407 camera_metadata_entry entry1 = 408 characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1); 409 BAIL_IF_EMPTY(entry1, env, TAG_COLORMATRIX1); 410 411 int32_t colorTransform1[entry1.count * 2]; 412 413 size_t ctr = 0; 414 for(size_t i = 0; i < entry1.count; ++i) { 415 colorTransform1[ctr++] = entry1.data.r[i].numerator; 416 colorTransform1[ctr++] = entry1.data.r[i].denominator; 417 } 418 419 BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX1, entry1.count, colorTransform1, TIFF_IFD_0), 420 env, TAG_COLORMATRIX1); 421 422 if (!singleIlluminant) { 423 camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2); 424 BAIL_IF_EMPTY(entry2, env, TAG_COLORMATRIX2); 425 int32_t colorTransform2[entry2.count * 2]; 426 427 ctr = 0; 428 for(size_t i = 0; i < entry2.count; ++i) { 429 colorTransform2[ctr++] = entry2.data.r[i].numerator; 430 colorTransform2[ctr++] = entry2.data.r[i].denominator; 431 } 432 433 BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX2, entry2.count, colorTransform2, TIFF_IFD_0), 434 env, TAG_COLORMATRIX2); 435 } 436 } 437 438 { 439 // Set calibration transforms 440 camera_metadata_entry entry1 = 441 characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1); 442 BAIL_IF_EMPTY(entry1, env, TAG_CAMERACALIBRATION1); 443 444 int32_t calibrationTransform1[entry1.count * 2]; 445 446 size_t ctr = 0; 447 for(size_t i = 0; i < entry1.count; ++i) { 448 calibrationTransform1[ctr++] = entry1.data.r[i].numerator; 449 calibrationTransform1[ctr++] = entry1.data.r[i].denominator; 450 } 451 452 BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, calibrationTransform1, 453 TIFF_IFD_0), env, TAG_CAMERACALIBRATION1); 454 455 if (!singleIlluminant) { 456 camera_metadata_entry entry2 = 457 characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2); 458 BAIL_IF_EMPTY(entry2, env, TAG_CAMERACALIBRATION2); 459 int32_t calibrationTransform2[entry2.count * 2]; 460 461 ctr = 0; 462 for(size_t i = 0; i < entry2.count; ++i) { 463 calibrationTransform2[ctr++] = entry2.data.r[i].numerator; 464 calibrationTransform2[ctr++] = entry2.data.r[i].denominator; 465 } 466 467 BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, calibrationTransform1, 468 TIFF_IFD_0), env, TAG_CAMERACALIBRATION2); 469 } 470 } 471 472 { 473 // Set forward transforms 474 camera_metadata_entry entry1 = 475 characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1); 476 BAIL_IF_EMPTY(entry1, env, TAG_FORWARDMATRIX1); 477 478 int32_t forwardTransform1[entry1.count * 2]; 479 480 size_t ctr = 0; 481 for(size_t i = 0; i < entry1.count; ++i) { 482 forwardTransform1[ctr++] = entry1.data.r[i].numerator; 483 forwardTransform1[ctr++] = entry1.data.r[i].denominator; 484 } 485 486 BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, forwardTransform1, 487 TIFF_IFD_0), env, TAG_FORWARDMATRIX1); 488 489 if (!singleIlluminant) { 490 camera_metadata_entry entry2 = 491 characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2); 492 BAIL_IF_EMPTY(entry2, env, TAG_FORWARDMATRIX2); 493 int32_t forwardTransform2[entry2.count * 2]; 494 495 ctr = 0; 496 for(size_t i = 0; i < entry2.count; ++i) { 497 forwardTransform2[ctr++] = entry2.data.r[i].numerator; 498 forwardTransform2[ctr++] = entry2.data.r[i].denominator; 499 } 500 501 BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, forwardTransform2, 502 TIFF_IFD_0), env, TAG_FORWARDMATRIX2); 503 } 504 } 505 506 { 507 // Set camera neutral 508 camera_metadata_entry entry = 509 results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT); 510 BAIL_IF_EMPTY(entry, env, TAG_ASSHOTNEUTRAL); 511 uint32_t cameraNeutral[entry.count * 2]; 512 513 size_t ctr = 0; 514 for(size_t i = 0; i < entry.count; ++i) { 515 cameraNeutral[ctr++] = 516 static_cast<uint32_t>(entry.data.r[i].numerator); 517 cameraNeutral[ctr++] = 518 static_cast<uint32_t>(entry.data.r[i].denominator); 519 } 520 521 BAIL_IF_INVALID(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral, 522 TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL); 523 } 524 525 { 526 // Setup data strips 527 // TODO: Switch to tiled implementation. 528 uint32_t offset = 0; 529 BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &offset, TIFF_IFD_0), env, 530 TAG_STRIPOFFSETS); 531 532 BAIL_IF_INVALID(writer->addEntry(TAG_ROWSPERSTRIP, 1, &imageHeight, TIFF_IFD_0), env, 533 TAG_ROWSPERSTRIP); 534 535 uint32_t byteCount = imageWidth * imageHeight * bitsPerSample * samplesPerPixel / 536 bitsPerByte; 537 BAIL_IF_INVALID(writer->addEntry(TAG_STRIPBYTECOUNTS, 1, &byteCount, TIFF_IFD_0), env, 538 TAG_STRIPBYTECOUNTS); 539 } 540 541 { 542 // Setup default crop + crop origin tags 543 uint32_t margin = 8; // Default margin recommended by Adobe for interpolation. 544 uint32_t dimensionLimit = 128; // Smallest image dimension crop margin from. 545 if (imageWidth >= dimensionLimit && imageHeight >= dimensionLimit) { 546 uint32_t defaultCropOrigin[] = {margin, margin}; 547 uint32_t defaultCropSize[] = {imageWidth - margin, imageHeight - margin}; 548 BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin, 549 TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN); 550 BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize, 551 TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE); 552 } 553 } 554 555 { 556 // Setup unique camera model tag 557 char model[PROPERTY_VALUE_MAX]; 558 property_get("ro.product.model", model, ""); 559 560 char manufacturer[PROPERTY_VALUE_MAX]; 561 property_get("ro.product.manufacturer", manufacturer, ""); 562 563 char brand[PROPERTY_VALUE_MAX]; 564 property_get("ro.product.brand", brand, ""); 565 566 String8 cameraModel(model); 567 cameraModel += "-"; 568 cameraModel += manufacturer; 569 cameraModel += "-"; 570 cameraModel += brand; 571 572 BAIL_IF_INVALID(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1, 573 reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env, 574 TAG_UNIQUECAMERAMODEL); 575 } 576 577 { 578 // Setup opcode List 2 579 camera_metadata_entry entry1 = 580 characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE); 581 BAIL_IF_EMPTY(entry1, env, TAG_OPCODELIST2); 582 uint32_t lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]); 583 uint32_t lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]); 584 585 camera_metadata_entry entry2 = 586 results.find(ANDROID_STATISTICS_LENS_SHADING_MAP); 587 BAIL_IF_EMPTY(entry2, env, TAG_OPCODELIST2); 588 if (entry2.count == lsmWidth * lsmHeight * 4) { 589 590 OpcodeListBuilder builder; 591 status_t err = builder.addGainMapsForMetadata(lsmWidth, 592 lsmHeight, 593 0, 594 0, 595 imageHeight, 596 imageWidth, 597 opcodeCfaLayout, 598 entry2.data.f); 599 if (err == OK) { 600 size_t listSize = builder.getSize(); 601 uint8_t opcodeListBuf[listSize]; 602 err = builder.buildOpList(opcodeListBuf); 603 if (err == OK) { 604 BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf, 605 TIFF_IFD_0), env, TAG_OPCODELIST2); 606 } else { 607 ALOGE("%s: Could not build Lens shading map opcode.", __FUNCTION__); 608 jniThrowRuntimeException(env, "failed to construct lens shading map opcode."); 609 } 610 } else { 611 ALOGE("%s: Could not add Lens shading map.", __FUNCTION__); 612 jniThrowRuntimeException(env, "failed to add lens shading map."); 613 } 614 } else { 615 ALOGW("%s: Lens shading map not present in results, skipping...", __FUNCTION__); 616 } 617 } 618 619 DngCreator_setCreator(env, thiz, writer); 620} 621 622static void DngCreator_destroy(JNIEnv* env, jobject thiz) { 623 ALOGV("%s:", __FUNCTION__); 624 DngCreator_setCreator(env, thiz, NULL); 625} 626 627static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz) { 628 ALOGV("%s:", __FUNCTION__); 629 jniThrowRuntimeException(env, "nativeSetOrientation is not implemented"); 630} 631 632static void DngCreator_nativeSetThumbnailBitmap(JNIEnv* env, jobject thiz, jobject bitmap) { 633 ALOGV("%s:", __FUNCTION__); 634 jniThrowRuntimeException(env, "nativeSetThumbnailBitmap is not implemented"); 635} 636 637static void DngCreator_nativeSetThumbnailImage(JNIEnv* env, jobject thiz, jint width, jint height, 638 jobject yBuffer, jint yRowStride, jint yPixStride, jobject uBuffer, jint uRowStride, 639 jint uPixStride, jobject vBuffer, jint vRowStride, jint vPixStride) { 640 ALOGV("%s:", __FUNCTION__); 641 jniThrowRuntimeException(env, "nativeSetThumbnailImage is not implemented"); 642} 643 644static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width, 645 jint height, jobject inBuffer, jint rowStride, jint pixStride) { 646 ALOGV("%s:", __FUNCTION__); 647 648 sp<JniOutputStream> out = new JniOutputStream(env, outStream); 649 if(env->ExceptionCheck()) { 650 ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__); 651 return; 652 } 653 654 uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer)); 655 if (pixelBytes == NULL) { 656 ALOGE("%s: Could not get native byte buffer", __FUNCTION__); 657 jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid bytebuffer"); 658 return; 659 } 660 661 TiffWriter* writer = DngCreator_getCreator(env, thiz); 662 if (writer == NULL) { 663 ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__); 664 jniThrowException(env, "java/lang/AssertionError", 665 "Write called with uninitialized DngCreator"); 666 return; 667 } 668 // TODO: handle lens shading map, etc. conversions for other raw buffer sizes. 669 uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, TIFF_IFD_0)->getData<uint32_t>()); 670 uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, TIFF_IFD_0)->getData<uint32_t>()); 671 if (metadataWidth != width) { 672 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \ 673 "Metadata width %d doesn't match image width %d", metadataWidth, width); 674 return; 675 } 676 677 if (metadataHeight != height) { 678 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \ 679 "Metadata height %d doesn't match image height %d", metadataHeight, height); 680 return; 681 } 682 683 uint32_t stripOffset = writer->getTotalSize(); 684 685 BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &stripOffset, TIFF_IFD_0), env, 686 TAG_STRIPOFFSETS); 687 688 if (writer->write(out.get()) != OK) { 689 if (!env->ExceptionCheck()) { 690 jniThrowException(env, "java/io/IOException", "Failed to write metadata"); 691 } 692 return; 693 } 694 695 size_t fullSize = rowStride * height; 696 jlong capacity = env->GetDirectBufferCapacity(inBuffer); 697 if (capacity < 0 || fullSize > capacity) { 698 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 699 "Invalid size %d for Image, size given in metadata is %d at current stride", 700 capacity, fullSize); 701 return; 702 } 703 704 if (pixStride == BYTES_PER_SAMPLE && rowStride == width * BYTES_PER_SAMPLE) { 705 if (out->write(pixelBytes, 0, fullSize) != OK || env->ExceptionCheck()) { 706 if (!env->ExceptionCheck()) { 707 jniThrowException(env, "java/io/IOException", "Failed to write pixel data"); 708 } 709 return; 710 } 711 } else if (pixStride == BYTES_PER_SAMPLE) { 712 for (size_t i = 0; i < height; ++i) { 713 if (out->write(pixelBytes, i * rowStride, pixStride * width) != OK || 714 env->ExceptionCheck()) { 715 if (!env->ExceptionCheck()) { 716 jniThrowException(env, "java/io/IOException", "Failed to write pixel data"); 717 } 718 return; 719 } 720 } 721 } else { 722 for (size_t i = 0; i < height; ++i) { 723 for (size_t j = 0; j < width; ++j) { 724 if (out->write(pixelBytes, i * rowStride + j * pixStride, 725 BYTES_PER_SAMPLE) != OK || !env->ExceptionCheck()) { 726 if (env->ExceptionCheck()) { 727 jniThrowException(env, "java/io/IOException", "Failed to write pixel data"); 728 } 729 return; 730 } 731 } 732 } 733 } 734 735} 736 737static void DngCreator_nativeWriteByteBuffer(JNIEnv* env, jobject thiz, jobject outStream, 738 jobject rawBuffer, jlong offset) { 739 ALOGV("%s:", __FUNCTION__); 740 jniThrowRuntimeException(env, "nativeWriteByteBuffer is not implemented."); 741} 742 743static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream, 744 jobject inStream, jlong offset) { 745 ALOGV("%s:", __FUNCTION__); 746 jniThrowRuntimeException(env, "nativeWriteInputStream is not implemented."); 747} 748 749} /*extern "C" */ 750 751static JNINativeMethod gDngCreatorMethods[] = { 752 {"nativeClassInit", "()V", (void*) DngCreator_nativeClassInit}, 753 {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;" 754 "Landroid/hardware/camera2/impl/CameraMetadataNative;)V", (void*) DngCreator_init}, 755 {"nativeDestroy", "()V", (void*) DngCreator_destroy}, 756 {"nativeSetOrientation", "(I)V", (void*) DngCreator_nativeSetOrientation}, 757 {"nativeSetThumbnailBitmap","(Landroid/graphics/Bitmap;)V", 758 (void*) DngCreator_nativeSetThumbnailBitmap}, 759 {"nativeSetThumbnailImage", 760 "(IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)V", 761 (void*) DngCreator_nativeSetThumbnailImage}, 762 {"nativeWriteImage", "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;II)V", 763 (void*) DngCreator_nativeWriteImage}, 764 {"nativeWriteByteBuffer", "(Ljava/io/OutputStream;Ljava/nio/ByteBuffer;J)V", 765 (void*) DngCreator_nativeWriteByteBuffer}, 766 {"nativeWriteInputStream", "(Ljava/io/OutputStream;Ljava/io/InputStream;J)V", 767 (void*) DngCreator_nativeWriteInputStream}, 768}; 769 770int register_android_hardware_camera2_DngCreator(JNIEnv *env) { 771 return AndroidRuntime::registerNativeMethods(env, 772 "android/hardware/camera2/DngCreator", gDngCreatorMethods, 773 NELEM(gDngCreatorMethods)); 774} 775