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