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     status_t err = OK;
64     uint32_t activeAreaWidth = activeAreaRight - activeAreaLeft;
65     uint32_t activeAreaHeight = activeAreaBottom - activeAreaTop;
66 
67     switch (cfa) {
68         case CFA_RGGB:
69         case CFA_GRBG:
70         case CFA_GBRG:
71         case CFA_BGGR:
72             err = addBayerGainMapsForMetadata(lsmWidth, lsmHeight, activeAreaWidth,
73                     activeAreaHeight, cfa, lensShadingMap);
74             break;
75         case CFA_NONE:
76             err = addMonochromeGainMapsForMetadata(lsmWidth, lsmHeight, activeAreaWidth,
77                     activeAreaHeight, lensShadingMap);
78             break;
79         default:
80             ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa);
81             err = BAD_VALUE;
82             break;
83     }
84     return err;
85 }
86 
addBayerGainMapsForMetadata(uint32_t lsmWidth,uint32_t lsmHeight,uint32_t activeAreaWidth,uint32_t activeAreaHeight,CfaLayout cfa,const float * lensShadingMap)87 status_t OpcodeListBuilder::addBayerGainMapsForMetadata(uint32_t lsmWidth,
88                                                    uint32_t lsmHeight,
89                                                    uint32_t activeAreaWidth,
90                                                    uint32_t activeAreaHeight,
91                                                    CfaLayout cfa,
92                                                    const float* lensShadingMap) {
93     uint32_t redTop = 0;
94     uint32_t redLeft = 0;
95     uint32_t greenEvenTop = 0;
96     uint32_t greenEvenLeft = 1;
97     uint32_t greenOddTop = 1;
98     uint32_t greenOddLeft = 0;
99     uint32_t blueTop = 1;
100     uint32_t blueLeft = 1;
101 
102     switch(cfa) {
103         case CFA_RGGB:
104             redTop = 0;
105             redLeft = 0;
106             greenEvenTop = 0;
107             greenEvenLeft = 1;
108             greenOddTop = 1;
109             greenOddLeft = 0;
110             blueTop = 1;
111             blueLeft = 1;
112             break;
113         case CFA_GRBG:
114             redTop = 0;
115             redLeft = 1;
116             greenEvenTop = 0;
117             greenEvenLeft = 0;
118             greenOddTop = 1;
119             greenOddLeft = 1;
120             blueTop = 1;
121             blueLeft = 0;
122             break;
123         case CFA_GBRG:
124             redTop = 1;
125             redLeft = 0;
126             greenEvenTop = 0;
127             greenEvenLeft = 0;
128             greenOddTop = 1;
129             greenOddLeft = 1;
130             blueTop = 0;
131             blueLeft = 1;
132             break;
133         case CFA_BGGR:
134             redTop = 1;
135             redLeft = 1;
136             greenEvenTop = 0;
137             greenEvenLeft = 1;
138             greenOddTop = 1;
139             greenOddLeft = 0;
140             blueTop = 0;
141             blueLeft = 0;
142             break;
143         default:
144             ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa);
145             return BAD_VALUE;
146     }
147 
148     std::vector<float> redMapVector(lsmWidth * lsmHeight);
149     float *redMap = redMapVector.data();
150 
151     std::vector<float> greenEvenMapVector(lsmWidth * lsmHeight);
152     float *greenEvenMap = greenEvenMapVector.data();
153 
154     std::vector<float> greenOddMapVector(lsmWidth * lsmHeight);
155     float *greenOddMap = greenOddMapVector.data();
156 
157     std::vector<float> blueMapVector(lsmWidth * lsmHeight);
158     float *blueMap = blueMapVector.data();
159 
160     double spacingV = 1.0 / std::max(1u, lsmHeight - 1);
161     double spacingH = 1.0 / std::max(1u, lsmWidth - 1);
162 
163     size_t lsmMapSize = lsmWidth * lsmHeight * 4;
164 
165     // Split lens shading map channels into separate arrays
166     size_t j = 0;
167     for (size_t i = 0; i < lsmMapSize; i += 4, ++j) {
168         redMap[j] = lensShadingMap[i + LSM_R_IND];
169         greenEvenMap[j] = lensShadingMap[i + LSM_GE_IND];
170         greenOddMap[j] = lensShadingMap[i + LSM_GO_IND];
171         blueMap[j] = lensShadingMap[i + LSM_B_IND];
172     }
173 
174     status_t err = addGainMap(/*top*/redTop,
175                               /*left*/redLeft,
176                               /*bottom*/activeAreaHeight,
177                               /*right*/activeAreaWidth,
178                               /*plane*/0,
179                               /*planes*/1,
180                               /*rowPitch*/2,
181                               /*colPitch*/2,
182                               /*mapPointsV*/lsmHeight,
183                               /*mapPointsH*/lsmWidth,
184                               /*mapSpacingV*/spacingV,
185                               /*mapSpacingH*/spacingH,
186                               /*mapOriginV*/0,
187                               /*mapOriginH*/0,
188                               /*mapPlanes*/1,
189                               /*mapGains*/redMap);
190     if (err != OK) return err;
191 
192     err = addGainMap(/*top*/greenEvenTop,
193                      /*left*/greenEvenLeft,
194                      /*bottom*/activeAreaHeight,
195                      /*right*/activeAreaWidth,
196                      /*plane*/0,
197                      /*planes*/1,
198                      /*rowPitch*/2,
199                      /*colPitch*/2,
200                      /*mapPointsV*/lsmHeight,
201                      /*mapPointsH*/lsmWidth,
202                      /*mapSpacingV*/spacingV,
203                      /*mapSpacingH*/spacingH,
204                      /*mapOriginV*/0,
205                      /*mapOriginH*/0,
206                      /*mapPlanes*/1,
207                      /*mapGains*/greenEvenMap);
208     if (err != OK) return err;
209 
210     err = addGainMap(/*top*/greenOddTop,
211                      /*left*/greenOddLeft,
212                      /*bottom*/activeAreaHeight,
213                      /*right*/activeAreaWidth,
214                      /*plane*/0,
215                      /*planes*/1,
216                      /*rowPitch*/2,
217                      /*colPitch*/2,
218                      /*mapPointsV*/lsmHeight,
219                      /*mapPointsH*/lsmWidth,
220                      /*mapSpacingV*/spacingV,
221                      /*mapSpacingH*/spacingH,
222                      /*mapOriginV*/0,
223                      /*mapOriginH*/0,
224                      /*mapPlanes*/1,
225                      /*mapGains*/greenOddMap);
226     if (err != OK) return err;
227 
228     err = addGainMap(/*top*/blueTop,
229                      /*left*/blueLeft,
230                      /*bottom*/activeAreaHeight,
231                      /*right*/activeAreaWidth,
232                      /*plane*/0,
233                      /*planes*/1,
234                      /*rowPitch*/2,
235                      /*colPitch*/2,
236                      /*mapPointsV*/lsmHeight,
237                      /*mapPointsH*/lsmWidth,
238                      /*mapSpacingV*/spacingV,
239                      /*mapSpacingH*/spacingH,
240                      /*mapOriginV*/0,
241                      /*mapOriginH*/0,
242                      /*mapPlanes*/1,
243                      /*mapGains*/blueMap);
244     return err;
245 }
246 
addMonochromeGainMapsForMetadata(uint32_t lsmWidth,uint32_t lsmHeight,uint32_t activeAreaWidth,uint32_t activeAreaHeight,const float * lensShadingMap)247 status_t OpcodeListBuilder::addMonochromeGainMapsForMetadata(uint32_t lsmWidth,
248                                                    uint32_t lsmHeight,
249                                                    uint32_t activeAreaWidth,
250                                                    uint32_t activeAreaHeight,
251                                                    const float* lensShadingMap) {
252     std::vector<float> mapVector(lsmWidth * lsmHeight);
253     float *map = mapVector.data();
254 
255     double spacingV = 1.0 / std::max(1u, lsmHeight - 1);
256     double spacingH = 1.0 / std::max(1u, lsmWidth - 1);
257 
258     size_t lsmMapSize = lsmWidth * lsmHeight * 4;
259 
260     // Split lens shading map channels into separate arrays
261     size_t j = 0;
262     for (size_t i = 0; i < lsmMapSize; i += 4, ++j) {
263         map[j] = lensShadingMap[i];
264     }
265 
266     status_t err = addGainMap(/*top*/0,
267                               /*left*/0,
268                               /*bottom*/activeAreaHeight,
269                               /*right*/activeAreaWidth,
270                               /*plane*/0,
271                               /*planes*/1,
272                               /*rowPitch*/1,
273                               /*colPitch*/1,
274                               /*mapPointsV*/lsmHeight,
275                               /*mapPointsH*/lsmWidth,
276                               /*mapSpacingV*/spacingV,
277                               /*mapSpacingH*/spacingH,
278                               /*mapOriginV*/0,
279                               /*mapOriginH*/0,
280                               /*mapPlanes*/1,
281                               /*mapGains*/map);
282     if (err != OK) return err;
283 
284     return err;
285 }
286 
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)287 status_t OpcodeListBuilder::addGainMap(uint32_t top,
288                                        uint32_t left,
289                                        uint32_t bottom,
290                                        uint32_t right,
291                                        uint32_t plane,
292                                        uint32_t planes,
293                                        uint32_t rowPitch,
294                                        uint32_t colPitch,
295                                        uint32_t mapPointsV,
296                                        uint32_t mapPointsH,
297                                        double mapSpacingV,
298                                        double mapSpacingH,
299                                        double mapOriginV,
300                                        double mapOriginH,
301                                        uint32_t mapPlanes,
302                                        const float* mapGains) {
303 
304     status_t err = addOpcodePreamble(GAIN_MAP_ID);
305     if (err != OK) return err;
306 
307     // Allow this opcode to be skipped if not supported
308     uint32_t flags = FLAG_OPTIONAL;
309 
310     err = mEndianOut.write(&flags, 0, 1);
311     if (err != OK) return err;
312 
313     const uint32_t NUMBER_INT_ARGS = 11;
314     const uint32_t NUMBER_DOUBLE_ARGS = 4;
315 
316     uint32_t totalSize = NUMBER_INT_ARGS * sizeof(uint32_t) + NUMBER_DOUBLE_ARGS * sizeof(double) +
317             mapPointsV * mapPointsH * mapPlanes * sizeof(float);
318 
319     err = mEndianOut.write(&totalSize, 0, 1);
320     if (err != OK) return err;
321 
322     // Batch writes as much as possible
323     uint32_t settings1[] = { top,
324                             left,
325                             bottom,
326                             right,
327                             plane,
328                             planes,
329                             rowPitch,
330                             colPitch,
331                             mapPointsV,
332                             mapPointsH };
333 
334     err = mEndianOut.write(settings1, 0, NELEMS(settings1));
335     if (err != OK) return err;
336 
337     double settings2[] = { mapSpacingV,
338                           mapSpacingH,
339                           mapOriginV,
340                           mapOriginH };
341 
342     err = mEndianOut.write(settings2, 0, NELEMS(settings2));
343     if (err != OK) return err;
344 
345     err = mEndianOut.write(&mapPlanes, 0, 1);
346     if (err != OK) return err;
347 
348     err = mEndianOut.write(mapGains, 0, mapPointsV * mapPointsH * mapPlanes);
349     if (err != OK) return err;
350 
351     mCount++;
352 
353     return OK;
354 }
355 
addWarpRectilinearForMetadata(const float * kCoeffs,uint32_t activeArrayWidth,uint32_t activeArrayHeight,float opticalCenterX,float opticalCenterY)356 status_t OpcodeListBuilder::addWarpRectilinearForMetadata(const float* kCoeffs,
357                                                           uint32_t activeArrayWidth,
358                                                           uint32_t activeArrayHeight,
359                                                           float opticalCenterX,
360                                                           float opticalCenterY) {
361     if (activeArrayWidth <= 1 || activeArrayHeight <= 1) {
362         ALOGE("%s: Cannot add opcode for active array with dimensions w=%" PRIu32 ", h=%" PRIu32,
363                 __FUNCTION__, activeArrayWidth, activeArrayHeight);
364         return BAD_VALUE;
365     }
366 
367     double normalizedOCX = opticalCenterX / static_cast<double>(activeArrayWidth);
368     double normalizedOCY = opticalCenterY / static_cast<double>(activeArrayHeight);
369 
370     normalizedOCX = CLAMP(normalizedOCX, 0, 1);
371     normalizedOCY = CLAMP(normalizedOCY, 0, 1);
372 
373     double coeffs[6] = {
374         kCoeffs[0],
375         kCoeffs[1],
376         kCoeffs[2],
377         kCoeffs[3],
378         kCoeffs[4],
379         kCoeffs[5]
380     };
381 
382     return addWarpRectilinear(/*numPlanes*/1,
383                               /*opticalCenterX*/normalizedOCX,
384                               /*opticalCenterY*/normalizedOCY,
385                               coeffs);
386 }
387 
addWarpRectilinear(uint32_t numPlanes,double opticalCenterX,double opticalCenterY,const double * kCoeffs)388 status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes,
389                                                double opticalCenterX,
390                                                double opticalCenterY,
391                                                const double* kCoeffs) {
392 
393     status_t err = addOpcodePreamble(WARP_RECTILINEAR_ID);
394     if (err != OK) return err;
395 
396     // Allow this opcode to be skipped if not supported
397     uint32_t flags = FLAG_OPTIONAL;
398 
399     err = mEndianOut.write(&flags, 0, 1);
400     if (err != OK) return err;
401 
402     const uint32_t NUMBER_CENTER_ARGS = 2;
403     const uint32_t NUMBER_COEFFS = numPlanes * 6;
404     uint32_t totalSize = (NUMBER_CENTER_ARGS + NUMBER_COEFFS) * sizeof(double) + sizeof(uint32_t);
405 
406     err = mEndianOut.write(&totalSize, 0, 1);
407     if (err != OK) return err;
408 
409     err = mEndianOut.write(&numPlanes, 0, 1);
410     if (err != OK) return err;
411 
412     err = mEndianOut.write(kCoeffs, 0, NUMBER_COEFFS);
413     if (err != OK) return err;
414 
415     err = mEndianOut.write(&opticalCenterX, 0, 1);
416     if (err != OK) return err;
417 
418     err = mEndianOut.write(&opticalCenterY, 0, 1);
419     if (err != OK) return err;
420 
421     mCount++;
422 
423     return OK;
424 }
425 
addBadPixelListForMetadata(const uint32_t * hotPixels,uint32_t xyPairCount,uint32_t colorFilterArrangement)426 status_t OpcodeListBuilder::addBadPixelListForMetadata(const uint32_t* hotPixels,
427                                                        uint32_t xyPairCount,
428                                                        uint32_t colorFilterArrangement) {
429     if (colorFilterArrangement > 3) {
430         ALOGE("%s:  Unknown color filter arrangement %" PRIu32, __FUNCTION__,
431                 colorFilterArrangement);
432         return BAD_VALUE;
433     }
434 
435     return addBadPixelList(colorFilterArrangement, xyPairCount, 0, hotPixels, nullptr);
436 }
437 
addBadPixelList(uint32_t bayerPhase,uint32_t badPointCount,uint32_t badRectCount,const uint32_t * badPointRowColPairs,const uint32_t * badRectTopLeftBottomRightTuples)438 status_t OpcodeListBuilder::addBadPixelList(uint32_t bayerPhase,
439                                             uint32_t badPointCount,
440                                             uint32_t badRectCount,
441                                             const uint32_t* badPointRowColPairs,
442                                             const uint32_t* badRectTopLeftBottomRightTuples) {
443 
444     status_t err = addOpcodePreamble(FIX_BAD_PIXELS_LIST);
445     if (err != OK) return err;
446 
447     // Allow this opcode to be skipped if not supported
448     uint32_t flags = FLAG_OPTIONAL;
449 
450     err = mEndianOut.write(&flags, 0, 1);
451     if (err != OK) return err;
452 
453     const uint32_t NUM_NON_VARLEN_FIELDS = 3;
454     const uint32_t SIZE_OF_POINT = 2;
455     const uint32_t SIZE_OF_RECT = 4;
456 
457     uint32_t totalSize =  (NUM_NON_VARLEN_FIELDS  + badPointCount * SIZE_OF_POINT +
458             badRectCount * SIZE_OF_RECT) * sizeof(uint32_t);
459     err = mEndianOut.write(&totalSize, 0, 1);
460     if (err != OK) return err;
461 
462     err = mEndianOut.write(&bayerPhase, 0, 1);
463     if (err != OK) return err;
464 
465     err = mEndianOut.write(&badPointCount, 0, 1);
466     if (err != OK) return err;
467 
468     err = mEndianOut.write(&badRectCount, 0, 1);
469     if (err != OK) return err;
470 
471     if (badPointCount > 0) {
472         err = mEndianOut.write(badPointRowColPairs, 0, SIZE_OF_POINT * badPointCount);
473         if (err != OK) return err;
474     }
475 
476     if (badRectCount > 0) {
477         err = mEndianOut.write(badRectTopLeftBottomRightTuples, 0, SIZE_OF_RECT * badRectCount);
478         if (err != OK) return err;
479     }
480 
481     mCount++;
482     return OK;
483 }
484 
addOpcodePreamble(uint32_t opcodeId)485 status_t OpcodeListBuilder::addOpcodePreamble(uint32_t opcodeId) {
486     status_t err = mEndianOut.write(&opcodeId, 0, 1);
487     if (err != OK) return err;
488 
489     uint8_t version[] = {1, 3, 0, 0};
490     err = mEndianOut.write(version, 0, NELEMS(version));
491     if (err != OK) return err;
492     return OK;
493 }
494 
495 } /*namespace img_utils*/
496 } /*namespace android*/
497