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 #include <img_utils/DngUtils.h> 18 19 #include <inttypes.h> 20 21 #include <algorithm> 22 #include <vector> 23 #include <math.h> 24 25 namespace android { 26 namespace img_utils { 27 28 OpcodeListBuilder::OpcodeListBuilder() : mCount(0), mOpList(), mEndianOut(&mOpList, BIG) { 29 if(mEndianOut.open() != OK) { 30 ALOGE("%s: Open failed.", __FUNCTION__); 31 } 32 } 33 34 OpcodeListBuilder::~OpcodeListBuilder() { 35 if(mEndianOut.close() != OK) { 36 ALOGE("%s: Close failed.", __FUNCTION__); 37 } 38 } 39 40 size_t OpcodeListBuilder::getSize() const { 41 return mOpList.getSize() + sizeof(mCount); 42 } 43 44 uint32_t OpcodeListBuilder::getCount() const { 45 return mCount; 46 } 47 48 status_t OpcodeListBuilder::buildOpList(uint8_t* buf) const { 49 uint32_t count = convertToBigEndian(mCount); 50 memcpy(buf, &count, sizeof(count)); 51 memcpy(buf + sizeof(count), mOpList.getArray(), mOpList.getSize()); 52 return OK; 53 } 54 55 status_t OpcodeListBuilder::addGainMapsForMetadata(uint32_t lsmWidth, 56 uint32_t lsmHeight, 57 uint32_t activeAreaTop, 58 uint32_t activeAreaLeft, 59 uint32_t activeAreaBottom, 60 uint32_t activeAreaRight, 61 CfaLayout cfa, 62 const float* lensShadingMap) { 63 status_t err = OK; 64 uint32_t activeAreaWidth = activeAreaRight - activeAreaLeft; 65 uint32_t activeAreaHeight = activeAreaBottom - activeAreaTop; 66 67 switch (cfa) { 68 case CFA_RGGB: 69 case CFA_GRBG: 70 case CFA_GBRG: 71 case CFA_BGGR: 72 err = addBayerGainMapsForMetadata(lsmWidth, lsmHeight, activeAreaWidth, 73 activeAreaHeight, cfa, lensShadingMap); 74 break; 75 case CFA_NONE: 76 err = addMonochromeGainMapsForMetadata(lsmWidth, lsmHeight, activeAreaWidth, 77 activeAreaHeight, lensShadingMap); 78 break; 79 default: 80 ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa); 81 err = BAD_VALUE; 82 break; 83 } 84 return err; 85 } 86 87 status_t OpcodeListBuilder::addBayerGainMapsForMetadata(uint32_t lsmWidth, 88 uint32_t lsmHeight, 89 uint32_t activeAreaWidth, 90 uint32_t activeAreaHeight, 91 CfaLayout cfa, 92 const float* lensShadingMap) { 93 uint32_t redTop = 0; 94 uint32_t redLeft = 0; 95 uint32_t greenEvenTop = 0; 96 uint32_t greenEvenLeft = 1; 97 uint32_t greenOddTop = 1; 98 uint32_t greenOddLeft = 0; 99 uint32_t blueTop = 1; 100 uint32_t blueLeft = 1; 101 102 switch(cfa) { 103 case CFA_RGGB: 104 redTop = 0; 105 redLeft = 0; 106 greenEvenTop = 0; 107 greenEvenLeft = 1; 108 greenOddTop = 1; 109 greenOddLeft = 0; 110 blueTop = 1; 111 blueLeft = 1; 112 break; 113 case CFA_GRBG: 114 redTop = 0; 115 redLeft = 1; 116 greenEvenTop = 0; 117 greenEvenLeft = 0; 118 greenOddTop = 1; 119 greenOddLeft = 1; 120 blueTop = 1; 121 blueLeft = 0; 122 break; 123 case CFA_GBRG: 124 redTop = 1; 125 redLeft = 0; 126 greenEvenTop = 0; 127 greenEvenLeft = 0; 128 greenOddTop = 1; 129 greenOddLeft = 1; 130 blueTop = 0; 131 blueLeft = 1; 132 break; 133 case CFA_BGGR: 134 redTop = 1; 135 redLeft = 1; 136 greenEvenTop = 0; 137 greenEvenLeft = 1; 138 greenOddTop = 1; 139 greenOddLeft = 0; 140 blueTop = 0; 141 blueLeft = 0; 142 break; 143 default: 144 ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa); 145 return BAD_VALUE; 146 } 147 148 std::vector<float> redMapVector(lsmWidth * lsmHeight); 149 float *redMap = redMapVector.data(); 150 151 std::vector<float> greenEvenMapVector(lsmWidth * lsmHeight); 152 float *greenEvenMap = greenEvenMapVector.data(); 153 154 std::vector<float> greenOddMapVector(lsmWidth * lsmHeight); 155 float *greenOddMap = greenOddMapVector.data(); 156 157 std::vector<float> blueMapVector(lsmWidth * lsmHeight); 158 float *blueMap = blueMapVector.data(); 159 160 double spacingV = 1.0 / std::max(1u, lsmHeight - 1); 161 double spacingH = 1.0 / std::max(1u, lsmWidth - 1); 162 163 size_t lsmMapSize = lsmWidth * lsmHeight * 4; 164 165 // Split lens shading map channels into separate arrays 166 size_t j = 0; 167 for (size_t i = 0; i < lsmMapSize; i += 4, ++j) { 168 redMap[j] = lensShadingMap[i + LSM_R_IND]; 169 greenEvenMap[j] = lensShadingMap[i + LSM_GE_IND]; 170 greenOddMap[j] = lensShadingMap[i + LSM_GO_IND]; 171 blueMap[j] = lensShadingMap[i + LSM_B_IND]; 172 } 173 174 status_t err = addGainMap(/*top*/redTop, 175 /*left*/redLeft, 176 /*bottom*/activeAreaHeight, 177 /*right*/activeAreaWidth, 178 /*plane*/0, 179 /*planes*/1, 180 /*rowPitch*/2, 181 /*colPitch*/2, 182 /*mapPointsV*/lsmHeight, 183 /*mapPointsH*/lsmWidth, 184 /*mapSpacingV*/spacingV, 185 /*mapSpacingH*/spacingH, 186 /*mapOriginV*/0, 187 /*mapOriginH*/0, 188 /*mapPlanes*/1, 189 /*mapGains*/redMap); 190 if (err != OK) return err; 191 192 err = addGainMap(/*top*/greenEvenTop, 193 /*left*/greenEvenLeft, 194 /*bottom*/activeAreaHeight, 195 /*right*/activeAreaWidth, 196 /*plane*/0, 197 /*planes*/1, 198 /*rowPitch*/2, 199 /*colPitch*/2, 200 /*mapPointsV*/lsmHeight, 201 /*mapPointsH*/lsmWidth, 202 /*mapSpacingV*/spacingV, 203 /*mapSpacingH*/spacingH, 204 /*mapOriginV*/0, 205 /*mapOriginH*/0, 206 /*mapPlanes*/1, 207 /*mapGains*/greenEvenMap); 208 if (err != OK) return err; 209 210 err = addGainMap(/*top*/greenOddTop, 211 /*left*/greenOddLeft, 212 /*bottom*/activeAreaHeight, 213 /*right*/activeAreaWidth, 214 /*plane*/0, 215 /*planes*/1, 216 /*rowPitch*/2, 217 /*colPitch*/2, 218 /*mapPointsV*/lsmHeight, 219 /*mapPointsH*/lsmWidth, 220 /*mapSpacingV*/spacingV, 221 /*mapSpacingH*/spacingH, 222 /*mapOriginV*/0, 223 /*mapOriginH*/0, 224 /*mapPlanes*/1, 225 /*mapGains*/greenOddMap); 226 if (err != OK) return err; 227 228 err = addGainMap(/*top*/blueTop, 229 /*left*/blueLeft, 230 /*bottom*/activeAreaHeight, 231 /*right*/activeAreaWidth, 232 /*plane*/0, 233 /*planes*/1, 234 /*rowPitch*/2, 235 /*colPitch*/2, 236 /*mapPointsV*/lsmHeight, 237 /*mapPointsH*/lsmWidth, 238 /*mapSpacingV*/spacingV, 239 /*mapSpacingH*/spacingH, 240 /*mapOriginV*/0, 241 /*mapOriginH*/0, 242 /*mapPlanes*/1, 243 /*mapGains*/blueMap); 244 return err; 245 } 246 247 status_t OpcodeListBuilder::addMonochromeGainMapsForMetadata(uint32_t lsmWidth, 248 uint32_t lsmHeight, 249 uint32_t activeAreaWidth, 250 uint32_t activeAreaHeight, 251 const float* lensShadingMap) { 252 std::vector<float> mapVector(lsmWidth * lsmHeight); 253 float *map = mapVector.data(); 254 255 double spacingV = 1.0 / std::max(1u, lsmHeight - 1); 256 double spacingH = 1.0 / std::max(1u, lsmWidth - 1); 257 258 size_t lsmMapSize = lsmWidth * lsmHeight * 4; 259 260 // Split lens shading map channels into separate arrays 261 size_t j = 0; 262 for (size_t i = 0; i < lsmMapSize; i += 4, ++j) { 263 map[j] = lensShadingMap[i]; 264 } 265 266 status_t err = addGainMap(/*top*/0, 267 /*left*/0, 268 /*bottom*/activeAreaHeight, 269 /*right*/activeAreaWidth, 270 /*plane*/0, 271 /*planes*/1, 272 /*rowPitch*/1, 273 /*colPitch*/1, 274 /*mapPointsV*/lsmHeight, 275 /*mapPointsH*/lsmWidth, 276 /*mapSpacingV*/spacingV, 277 /*mapSpacingH*/spacingH, 278 /*mapOriginV*/0, 279 /*mapOriginH*/0, 280 /*mapPlanes*/1, 281 /*mapGains*/map); 282 if (err != OK) return err; 283 284 return err; 285 } 286 287 status_t OpcodeListBuilder::addGainMap(uint32_t top, 288 uint32_t left, 289 uint32_t bottom, 290 uint32_t right, 291 uint32_t plane, 292 uint32_t planes, 293 uint32_t rowPitch, 294 uint32_t colPitch, 295 uint32_t mapPointsV, 296 uint32_t mapPointsH, 297 double mapSpacingV, 298 double mapSpacingH, 299 double mapOriginV, 300 double mapOriginH, 301 uint32_t mapPlanes, 302 const float* mapGains) { 303 304 status_t err = addOpcodePreamble(GAIN_MAP_ID); 305 if (err != OK) return err; 306 307 // Allow this opcode to be skipped if not supported 308 uint32_t flags = FLAG_OPTIONAL; 309 310 err = mEndianOut.write(&flags, 0, 1); 311 if (err != OK) return err; 312 313 const uint32_t NUMBER_INT_ARGS = 11; 314 const uint32_t NUMBER_DOUBLE_ARGS = 4; 315 316 uint32_t totalSize = NUMBER_INT_ARGS * sizeof(uint32_t) + NUMBER_DOUBLE_ARGS * sizeof(double) + 317 mapPointsV * mapPointsH * mapPlanes * sizeof(float); 318 319 err = mEndianOut.write(&totalSize, 0, 1); 320 if (err != OK) return err; 321 322 // Batch writes as much as possible 323 uint32_t settings1[] = { top, 324 left, 325 bottom, 326 right, 327 plane, 328 planes, 329 rowPitch, 330 colPitch, 331 mapPointsV, 332 mapPointsH }; 333 334 err = mEndianOut.write(settings1, 0, NELEMS(settings1)); 335 if (err != OK) return err; 336 337 double settings2[] = { mapSpacingV, 338 mapSpacingH, 339 mapOriginV, 340 mapOriginH }; 341 342 err = mEndianOut.write(settings2, 0, NELEMS(settings2)); 343 if (err != OK) return err; 344 345 err = mEndianOut.write(&mapPlanes, 0, 1); 346 if (err != OK) return err; 347 348 err = mEndianOut.write(mapGains, 0, mapPointsV * mapPointsH * mapPlanes); 349 if (err != OK) return err; 350 351 mCount++; 352 353 return OK; 354 } 355 356 status_t OpcodeListBuilder::addWarpRectilinearForMetadata(const float* kCoeffs, 357 uint32_t activeArrayWidth, 358 uint32_t activeArrayHeight, 359 float opticalCenterX, 360 float opticalCenterY) { 361 if (activeArrayWidth <= 1 || activeArrayHeight <= 1) { 362 ALOGE("%s: Cannot add opcode for active array with dimensions w=%" PRIu32 ", h=%" PRIu32, 363 __FUNCTION__, activeArrayWidth, activeArrayHeight); 364 return BAD_VALUE; 365 } 366 367 double normalizedOCX = opticalCenterX / static_cast<double>(activeArrayWidth); 368 double normalizedOCY = opticalCenterY / static_cast<double>(activeArrayHeight); 369 370 normalizedOCX = CLAMP(normalizedOCX, 0, 1); 371 normalizedOCY = CLAMP(normalizedOCY, 0, 1); 372 373 double coeffs[6] = { 374 kCoeffs[0], 375 kCoeffs[1], 376 kCoeffs[2], 377 kCoeffs[3], 378 kCoeffs[4], 379 kCoeffs[5] 380 }; 381 382 return addWarpRectilinear(/*numPlanes*/1, 383 /*opticalCenterX*/normalizedOCX, 384 /*opticalCenterY*/normalizedOCY, 385 coeffs); 386 } 387 388 status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes, 389 double opticalCenterX, 390 double opticalCenterY, 391 const double* kCoeffs) { 392 393 status_t err = addOpcodePreamble(WARP_RECTILINEAR_ID); 394 if (err != OK) return err; 395 396 // Allow this opcode to be skipped if not supported 397 uint32_t flags = FLAG_OPTIONAL; 398 399 err = mEndianOut.write(&flags, 0, 1); 400 if (err != OK) return err; 401 402 const uint32_t NUMBER_CENTER_ARGS = 2; 403 const uint32_t NUMBER_COEFFS = numPlanes * 6; 404 uint32_t totalSize = (NUMBER_CENTER_ARGS + NUMBER_COEFFS) * sizeof(double) + sizeof(uint32_t); 405 406 err = mEndianOut.write(&totalSize, 0, 1); 407 if (err != OK) return err; 408 409 err = mEndianOut.write(&numPlanes, 0, 1); 410 if (err != OK) return err; 411 412 err = mEndianOut.write(kCoeffs, 0, NUMBER_COEFFS); 413 if (err != OK) return err; 414 415 err = mEndianOut.write(&opticalCenterX, 0, 1); 416 if (err != OK) return err; 417 418 err = mEndianOut.write(&opticalCenterY, 0, 1); 419 if (err != OK) return err; 420 421 mCount++; 422 423 return OK; 424 } 425 426 status_t OpcodeListBuilder::addBadPixelListForMetadata(const uint32_t* hotPixels, 427 uint32_t xyPairCount, 428 uint32_t colorFilterArrangement) { 429 if (colorFilterArrangement > 3) { 430 ALOGE("%s: Unknown color filter arrangement %" PRIu32, __FUNCTION__, 431 colorFilterArrangement); 432 return BAD_VALUE; 433 } 434 435 return addBadPixelList(colorFilterArrangement, xyPairCount, 0, hotPixels, nullptr); 436 } 437 438 status_t OpcodeListBuilder::addBadPixelList(uint32_t bayerPhase, 439 uint32_t badPointCount, 440 uint32_t badRectCount, 441 const uint32_t* badPointRowColPairs, 442 const uint32_t* badRectTopLeftBottomRightTuples) { 443 444 status_t err = addOpcodePreamble(FIX_BAD_PIXELS_LIST); 445 if (err != OK) return err; 446 447 // Allow this opcode to be skipped if not supported 448 uint32_t flags = FLAG_OPTIONAL; 449 450 err = mEndianOut.write(&flags, 0, 1); 451 if (err != OK) return err; 452 453 const uint32_t NUM_NON_VARLEN_FIELDS = 3; 454 const uint32_t SIZE_OF_POINT = 2; 455 const uint32_t SIZE_OF_RECT = 4; 456 457 uint32_t totalSize = (NUM_NON_VARLEN_FIELDS + badPointCount * SIZE_OF_POINT + 458 badRectCount * SIZE_OF_RECT) * sizeof(uint32_t); 459 err = mEndianOut.write(&totalSize, 0, 1); 460 if (err != OK) return err; 461 462 err = mEndianOut.write(&bayerPhase, 0, 1); 463 if (err != OK) return err; 464 465 err = mEndianOut.write(&badPointCount, 0, 1); 466 if (err != OK) return err; 467 468 err = mEndianOut.write(&badRectCount, 0, 1); 469 if (err != OK) return err; 470 471 if (badPointCount > 0) { 472 err = mEndianOut.write(badPointRowColPairs, 0, SIZE_OF_POINT * badPointCount); 473 if (err != OK) return err; 474 } 475 476 if (badRectCount > 0) { 477 err = mEndianOut.write(badRectTopLeftBottomRightTuples, 0, SIZE_OF_RECT * badRectCount); 478 if (err != OK) return err; 479 } 480 481 mCount++; 482 return OK; 483 } 484 485 status_t OpcodeListBuilder::addOpcodePreamble(uint32_t opcodeId) { 486 status_t err = mEndianOut.write(&opcodeId, 0, 1); 487 if (err != OK) return err; 488 489 uint8_t version[] = {1, 3, 0, 0}; 490 err = mEndianOut.write(version, 0, NELEMS(version)); 491 if (err != OK) return err; 492 return OK; 493 } 494 495 } /*namespace img_utils*/ 496 } /*namespace android*/ 497