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