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 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
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)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
addWarpRectilinearForMetadata(const float * kCoeffs,uint32_t activeArrayWidth,uint32_t activeArrayHeight,float opticalCenterX,float opticalCenterY)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
addWarpRectilinear(uint32_t numPlanes,double opticalCenterX,double opticalCenterY,const double * kCoeffs)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
addBadPixelListForMetadata(const uint32_t * hotPixels,uint32_t xyPairCount,uint32_t colorFilterArrangement)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
addBadPixelList(uint32_t bayerPhase,uint32_t badPointCount,uint32_t badRectCount,const uint32_t * badPointRowColPairs,const uint32_t * badRectTopLeftBottomRightTuples)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
addOpcodePreamble(uint32_t opcodeId)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