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