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
24 namespace android {
25 namespace img_utils {
26
OpcodeListBuilder()27 OpcodeListBuilder::OpcodeListBuilder() : mCount(0), mOpList(), mEndianOut(&mOpList, BIG) {
28 if(mEndianOut.open() != OK) {
29 ALOGE("%s: Open failed.", __FUNCTION__);
30 }
31 }
32
~OpcodeListBuilder()33 OpcodeListBuilder::~OpcodeListBuilder() {
34 if(mEndianOut.close() != OK) {
35 ALOGE("%s: Close failed.", __FUNCTION__);
36 }
37 }
38
getSize() const39 size_t OpcodeListBuilder::getSize() const {
40 return mOpList.getSize() + sizeof(mCount);
41 }
42
getCount() const43 uint32_t OpcodeListBuilder::getCount() const {
44 return mCount;
45 }
46
buildOpList(uint8_t * buf) const47 status_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
addGainMapsForMetadata(uint32_t lsmWidth,uint32_t lsmHeight,uint32_t activeAreaTop,uint32_t activeAreaLeft,uint32_t activeAreaBottom,uint32_t activeAreaRight,CfaLayout cfa,const float * lensShadingMap)54 status_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
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)218 status_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
addWarpRectilinearForMetadata(const float * kCoeffs,uint32_t activeArrayWidth,uint32_t activeArrayHeight,float opticalCenterX,float opticalCenterY)287 status_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
addWarpRectilinear(uint32_t numPlanes,double opticalCenterX,double opticalCenterY,const double * kCoeffs)334 status_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
addBadPixelListForMetadata(const uint32_t * hotPixels,uint32_t xyPairCount,uint32_t colorFilterArrangement)372 status_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
addBadPixelList(uint32_t bayerPhase,uint32_t badPointCount,uint32_t badRectCount,const uint32_t * badPointRowColPairs,const uint32_t * badRectTopLeftBottomRightTuples)384 status_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
addOpcodePreamble(uint32_t opcodeId)431 status_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