blob: 9473dcea9286829d0424f4131d7ed2c1edf97c3b [file] [log] [blame]
Ruben Brunke5077212014-04-28 16:39:12 -07001/*
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
Ruben Brunk0f212b72015-06-05 17:03:05 -070019#include <inttypes.h>
20
21#include <math.h>
22
Ruben Brunke5077212014-04-28 16:39:12 -070023namespace android {
24namespace img_utils {
25
Ruben Brunk3fe14352014-06-04 15:35:21 -070026OpcodeListBuilder::OpcodeListBuilder() : mCount(0), mOpList(), mEndianOut(&mOpList, BIG) {
Ruben Brunke5077212014-04-28 16:39:12 -070027 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
Ruben Brunkbdd36872015-08-03 11:36:40 -0700227 status_t err = addOpcodePreamble(GAIN_MAP_ID);
Ruben Brunke5077212014-04-28 16:39:12 -0700228 if (err != OK) return err;
229
Ruben Brunk0f212b72015-06-05 17:03:05 -0700230 // Allow this opcode to be skipped if not supported
Ruben Brunk482e0232014-10-01 12:59:57 -0700231 uint32_t flags = FLAG_OPTIONAL;
232
Ruben Brunke5077212014-04-28 16:39:12 -0700233 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
Ruben Brunk0f212b72015-06-05 17:03:05 -0700279status_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
Ruben Brunkbdd36872015-08-03 11:36:40 -0700331 status_t err = addOpcodePreamble(WARP_RECTILINEAR_ID);
Ruben Brunk0f212b72015-06-05 17:03:05 -0700332 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
Ruben Brunkbdd36872015-08-03 11:36:40 -0700364status_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
Ruben Brunke5077212014-04-28 16:39:12 -0700433} /*namespace img_utils*/
434} /*namespace android*/