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