blob: b21340381b9f3359f5c83a12980f06d2396d55c4 [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
227 uint32_t opcodeId = GAIN_MAP_ID;
228
229 status_t err = mEndianOut.write(&opcodeId, 0, 1);
230 if (err != OK) return err;
231
232 uint8_t version[] = {1, 3, 0, 0};
233 err = mEndianOut.write(version, 0, NELEMS(version));
234 if (err != OK) return err;
235
Ruben Brunk0f212b72015-06-05 17:03:05 -0700236 // Allow this opcode to be skipped if not supported
Ruben Brunk482e0232014-10-01 12:59:57 -0700237 uint32_t flags = FLAG_OPTIONAL;
238
Ruben Brunke5077212014-04-28 16:39:12 -0700239 err = mEndianOut.write(&flags, 0, 1);
240 if (err != OK) return err;
241
242 const uint32_t NUMBER_INT_ARGS = 11;
243 const uint32_t NUMBER_DOUBLE_ARGS = 4;
244
245 uint32_t totalSize = NUMBER_INT_ARGS * sizeof(uint32_t) + NUMBER_DOUBLE_ARGS * sizeof(double) +
246 mapPointsV * mapPointsH * mapPlanes * sizeof(float);
247
248 err = mEndianOut.write(&totalSize, 0, 1);
249 if (err != OK) return err;
250
251 // Batch writes as much as possible
252 uint32_t settings1[] = { top,
253 left,
254 bottom,
255 right,
256 plane,
257 planes,
258 rowPitch,
259 colPitch,
260 mapPointsV,
261 mapPointsH };
262
263 err = mEndianOut.write(settings1, 0, NELEMS(settings1));
264 if (err != OK) return err;
265
266 double settings2[] = { mapSpacingV,
267 mapSpacingH,
268 mapOriginV,
269 mapOriginH };
270
271 err = mEndianOut.write(settings2, 0, NELEMS(settings2));
272 if (err != OK) return err;
273
274 err = mEndianOut.write(&mapPlanes, 0, 1);
275 if (err != OK) return err;
276
277 err = mEndianOut.write(mapGains, 0, mapPointsV * mapPointsH * mapPlanes);
278 if (err != OK) return err;
279
280 mCount++;
281
282 return OK;
283}
284
Ruben Brunk0f212b72015-06-05 17:03:05 -0700285status_t OpcodeListBuilder::addWarpRectilinearForMetadata(const float* kCoeffs,
286 uint32_t activeArrayWidth,
287 uint32_t activeArrayHeight,
288 float opticalCenterX,
289 float opticalCenterY) {
290 if (activeArrayWidth <= 1 || activeArrayHeight <= 1) {
291 ALOGE("%s: Cannot add opcode for active array with dimensions w=%" PRIu32 ", h=%" PRIu32,
292 __FUNCTION__, activeArrayWidth, activeArrayHeight);
293 return BAD_VALUE;
294 }
295
296 double normalizedOCX = opticalCenterX / static_cast<double>(activeArrayWidth - 1);
297 double normalizedOCY = opticalCenterY / static_cast<double>(activeArrayHeight - 1);
298
299 normalizedOCX = CLAMP(normalizedOCX, 0, 1);
300 normalizedOCY = CLAMP(normalizedOCY, 0, 1);
301
302 // Conversion factors from Camera2 K factors to DNG spec. K factors:
303 //
304 // Note: these are necessary because our unit system assumes a
305 // normalized max radius of sqrt(2), whereas the DNG spec's
306 // WarpRectilinear opcode assumes a normalized max radius of 1.
307 // Thus, each K coefficient must include the domain scaling
308 // factor (the DNG domain is scaled by sqrt(2) to emulate the
309 // domain used by the Camera2 specification).
310
311 const double c_0 = sqrt(2);
312 const double c_1 = 2 * sqrt(2);
313 const double c_2 = 4 * sqrt(2);
314 const double c_3 = 8 * sqrt(2);
315 const double c_4 = 2;
316 const double c_5 = 2;
317
318 const double coeffs[] = { c_0 * kCoeffs[0],
319 c_1 * kCoeffs[1],
320 c_2 * kCoeffs[2],
321 c_3 * kCoeffs[3],
322 c_4 * kCoeffs[4],
323 c_5 * kCoeffs[5] };
324
325
326 return addWarpRectilinear(/*numPlanes*/1,
327 /*opticalCenterX*/normalizedOCX,
328 /*opticalCenterY*/normalizedOCY,
329 coeffs);
330}
331
332status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes,
333 double opticalCenterX,
334 double opticalCenterY,
335 const double* kCoeffs) {
336
337 uint32_t opcodeId = WARP_RECTILINEAR_ID;
338
339 status_t err = mEndianOut.write(&opcodeId, 0, 1);
340 if (err != OK) return err;
341
342 uint8_t version[] = {1, 3, 0, 0};
343 err = mEndianOut.write(version, 0, NELEMS(version));
344 if (err != OK) return err;
345
346 // Allow this opcode to be skipped if not supported
347 uint32_t flags = FLAG_OPTIONAL;
348
349 err = mEndianOut.write(&flags, 0, 1);
350 if (err != OK) return err;
351
352 const uint32_t NUMBER_CENTER_ARGS = 2;
353 const uint32_t NUMBER_COEFFS = numPlanes * 6;
354 uint32_t totalSize = (NUMBER_CENTER_ARGS + NUMBER_COEFFS) * sizeof(double) + sizeof(uint32_t);
355
356 err = mEndianOut.write(&totalSize, 0, 1);
357 if (err != OK) return err;
358
359 err = mEndianOut.write(&numPlanes, 0, 1);
360 if (err != OK) return err;
361
362 err = mEndianOut.write(kCoeffs, 0, NUMBER_COEFFS);
363 if (err != OK) return err;
364
365 err = mEndianOut.write(&opticalCenterX, 0, 1);
366 if (err != OK) return err;
367
368 err = mEndianOut.write(&opticalCenterY, 0, 1);
369 if (err != OK) return err;
370
371 mCount++;
372
373 return OK;
374}
375
Ruben Brunke5077212014-04-28 16:39:12 -0700376} /*namespace img_utils*/
377} /*namespace android*/