• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <math.h>
22 
23 namespace android {
24 namespace img_utils {
25 
OpcodeListBuilder()26 OpcodeListBuilder::OpcodeListBuilder() : mCount(0), mOpList(), mEndianOut(&mOpList, BIG) {
27     if(mEndianOut.open() != OK) {
28         ALOGE("%s: Open failed.", __FUNCTION__);
29     }
30 }
31 
~OpcodeListBuilder()32 OpcodeListBuilder::~OpcodeListBuilder() {
33     if(mEndianOut.close() != OK) {
34         ALOGE("%s: Close failed.", __FUNCTION__);
35     }
36 }
37 
getSize() const38 size_t OpcodeListBuilder::getSize() const {
39     return mOpList.getSize() + sizeof(mCount);
40 }
41 
getCount() const42 uint32_t OpcodeListBuilder::getCount() const {
43     return mCount;
44 }
45 
buildOpList(uint8_t * buf) const46 status_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 
addGainMapsForMetadata(uint32_t lsmWidth,uint32_t lsmHeight,uint32_t activeAreaTop,uint32_t activeAreaLeft,uint32_t activeAreaBottom,uint32_t activeAreaRight,CfaLayout cfa,const float * lensShadingMap)53 status_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 
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)210 status_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     status_t err = addOpcodePreamble(GAIN_MAP_ID);
228     if (err != OK) return err;
229 
230     // Allow this opcode to be skipped if not supported
231     uint32_t flags = FLAG_OPTIONAL;
232 
233     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 
addWarpRectilinearForMetadata(const float * kCoeffs,uint32_t activeArrayWidth,uint32_t activeArrayHeight,float opticalCenterX,float opticalCenterY)279 status_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 
addWarpRectilinear(uint32_t numPlanes,double opticalCenterX,double opticalCenterY,const double * kCoeffs)326 status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes,
327                                                double opticalCenterX,
328                                                double opticalCenterY,
329                                                const double* kCoeffs) {
330 
331     status_t err = addOpcodePreamble(WARP_RECTILINEAR_ID);
332     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 
addBadPixelListForMetadata(const uint32_t * hotPixels,uint32_t xyPairCount,uint32_t colorFilterArrangement)364 status_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 
addBadPixelList(uint32_t bayerPhase,uint32_t badPointCount,uint32_t badRectCount,const uint32_t * badPointRowColPairs,const uint32_t * badRectTopLeftBottomRightTuples)376 status_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 
addOpcodePreamble(uint32_t opcodeId)423 status_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 
433 } /*namespace img_utils*/
434 } /*namespace android*/
435