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