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
OpcodeListBuilder()28 OpcodeListBuilder::OpcodeListBuilder() : mCount(0), mOpList(), mEndianOut(&mOpList, BIG) {
29 if(mEndianOut.open() != OK) {
30 ALOGE("%s: Open failed.", __FUNCTION__);
31 }
32 }
33
~OpcodeListBuilder()34 OpcodeListBuilder::~OpcodeListBuilder() {
35 if(mEndianOut.close() != OK) {
36 ALOGE("%s: Close failed.", __FUNCTION__);
37 }
38 }
39
getSize() const40 size_t OpcodeListBuilder::getSize() const {
41 return mOpList.getSize() + sizeof(mCount);
42 }
43
getCount() const44 uint32_t OpcodeListBuilder::getCount() const {
45 return mCount;
46 }
47
buildOpList(uint8_t * buf) const48 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
addGainMapsForMetadata(uint32_t lsmWidth,uint32_t lsmHeight,uint32_t activeAreaTop,uint32_t activeAreaLeft,uint32_t activeAreaBottom,uint32_t activeAreaRight,CfaLayout cfa,const float * lensShadingMap)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
addBayerGainMapsForMetadata(uint32_t lsmWidth,uint32_t lsmHeight,uint32_t activeAreaWidth,uint32_t activeAreaHeight,CfaLayout cfa,const float * lensShadingMap)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
addMonochromeGainMapsForMetadata(uint32_t lsmWidth,uint32_t lsmHeight,uint32_t activeAreaWidth,uint32_t activeAreaHeight,const float * lensShadingMap)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
addGainMap(uint32_t top,uint32_t left,uint32_t bottom,uint32_t right,uint32_t plane,uint32_t planes,uint32_t rowPitch,uint32_t colPitch,uint32_t mapPointsV,uint32_t mapPointsH,double mapSpacingV,double mapSpacingH,double mapOriginV,double mapOriginH,uint32_t mapPlanes,const float * mapGains)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
addWarpRectilinearForMetadata(const float * kCoeffs,uint32_t activeArrayWidth,uint32_t activeArrayHeight,float opticalCenterX,float opticalCenterY)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
addWarpRectilinear(uint32_t numPlanes,double opticalCenterX,double opticalCenterY,const double * kCoeffs)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
addBadPixelListForMetadata(const uint32_t * hotPixels,uint32_t xyPairCount,uint32_t colorFilterArrangement)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
addBadPixelList(uint32_t bayerPhase,uint32_t badPointCount,uint32_t badRectCount,const uint32_t * badPointRowColPairs,const uint32_t * badRectTopLeftBottomRightTuples)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
addOpcodePreamble(uint32_t opcodeId)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