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
19namespace android {
20namespace img_utils {
21
22OpcodeListBuilder::OpcodeListBuilder() : mCount(0), mOpList(), mEndianOut(&mOpList, BIG) {
23    if(mEndianOut.open() != OK) {
24        ALOGE("%s: Open failed.", __FUNCTION__);
25    }
26}
27
28OpcodeListBuilder::~OpcodeListBuilder() {
29    if(mEndianOut.close() != OK) {
30        ALOGE("%s: Close failed.", __FUNCTION__);
31    }
32}
33
34size_t OpcodeListBuilder::getSize() const {
35    return mOpList.getSize() + sizeof(mCount);
36}
37
38uint32_t OpcodeListBuilder::getCount() const {
39    return mCount;
40}
41
42status_t OpcodeListBuilder::buildOpList(uint8_t* buf) const {
43    uint32_t count = convertToBigEndian(mCount);
44    memcpy(buf, &count, sizeof(count));
45    memcpy(buf + sizeof(count), mOpList.getArray(), mOpList.getSize());
46    return OK;
47}
48
49status_t OpcodeListBuilder::addGainMapsForMetadata(uint32_t lsmWidth,
50                                                   uint32_t lsmHeight,
51                                                   uint32_t activeAreaTop,
52                                                   uint32_t activeAreaLeft,
53                                                   uint32_t activeAreaBottom,
54                                                   uint32_t activeAreaRight,
55                                                   CfaLayout cfa,
56                                                   const float* lensShadingMap) {
57    uint32_t activeAreaWidth = activeAreaRight - activeAreaLeft;
58    uint32_t activeAreaHeight = activeAreaBottom - activeAreaTop;
59    double spacingV = 1.0 / lsmHeight;
60    double spacingH = 1.0 / lsmWidth;
61
62    float redMap[lsmWidth * lsmHeight];
63    float greenEvenMap[lsmWidth * lsmHeight];
64    float greenOddMap[lsmWidth * lsmHeight];
65    float blueMap[lsmWidth * lsmHeight];
66
67    size_t lsmMapSize = lsmWidth * lsmHeight * 4;
68
69    // Split lens shading map channels into separate arrays
70    size_t j = 0;
71    for (size_t i = 0; i < lsmMapSize; i += 4, ++j) {
72        redMap[j] = lensShadingMap[i + LSM_R_IND];
73        greenEvenMap[j] = lensShadingMap[i + LSM_GE_IND];
74        greenOddMap[j] = lensShadingMap[i + LSM_GO_IND];
75        blueMap[j] = lensShadingMap[i + LSM_B_IND];
76    }
77
78    uint32_t redTop = 0;
79    uint32_t redLeft = 0;
80    uint32_t greenEvenTop = 0;
81    uint32_t greenEvenLeft = 1;
82    uint32_t greenOddTop = 1;
83    uint32_t greenOddLeft = 0;
84    uint32_t blueTop = 1;
85    uint32_t blueLeft = 1;
86
87    switch(cfa) {
88        case CFA_RGGB:
89            redTop = 0;
90            redLeft = 0;
91            greenEvenTop = 0;
92            greenEvenLeft = 1;
93            greenOddTop = 1;
94            greenOddLeft = 0;
95            blueTop = 1;
96            blueLeft = 1;
97            break;
98        case CFA_GRBG:
99            redTop = 0;
100            redLeft = 1;
101            greenEvenTop = 0;
102            greenEvenLeft = 0;
103            greenOddTop = 1;
104            greenOddLeft = 1;
105            blueTop = 1;
106            blueLeft = 0;
107            break;
108        case CFA_GBRG:
109            redTop = 1;
110            redLeft = 0;
111            greenEvenTop = 0;
112            greenEvenLeft = 0;
113            greenOddTop = 1;
114            greenOddLeft = 1;
115            blueTop = 0;
116            blueLeft = 1;
117            break;
118        case CFA_BGGR:
119            redTop = 1;
120            redLeft = 1;
121            greenEvenTop = 0;
122            greenEvenLeft = 1;
123            greenOddTop = 1;
124            greenOddLeft = 0;
125            blueTop = 0;
126            blueLeft = 0;
127            break;
128        default:
129            ALOGE("%s: Unknown CFA layout %d", __FUNCTION__, cfa);
130            return BAD_VALUE;
131    }
132
133    status_t err = addGainMap(/*top*/redTop,
134                              /*left*/redLeft,
135                              /*bottom*/activeAreaHeight - 1,
136                              /*right*/activeAreaWidth - 1,
137                              /*plane*/0,
138                              /*planes*/1,
139                              /*rowPitch*/2,
140                              /*colPitch*/2,
141                              /*mapPointsV*/lsmHeight,
142                              /*mapPointsH*/lsmWidth,
143                              /*mapSpacingV*/spacingV,
144                              /*mapSpacingH*/spacingH,
145                              /*mapOriginV*/0,
146                              /*mapOriginH*/0,
147                              /*mapPlanes*/1,
148                              /*mapGains*/redMap);
149    if (err != OK) return err;
150
151    err = addGainMap(/*top*/greenEvenTop,
152                     /*left*/greenEvenLeft,
153                     /*bottom*/activeAreaHeight - 1,
154                     /*right*/activeAreaWidth - 1,
155                     /*plane*/0,
156                     /*planes*/1,
157                     /*rowPitch*/2,
158                     /*colPitch*/2,
159                     /*mapPointsV*/lsmHeight,
160                     /*mapPointsH*/lsmWidth,
161                     /*mapSpacingV*/spacingV,
162                     /*mapSpacingH*/spacingH,
163                     /*mapOriginV*/0,
164                     /*mapOriginH*/0,
165                     /*mapPlanes*/1,
166                     /*mapGains*/greenEvenMap);
167    if (err != OK) return err;
168
169    err = addGainMap(/*top*/greenOddTop,
170                     /*left*/greenOddLeft,
171                     /*bottom*/activeAreaHeight - 1,
172                     /*right*/activeAreaWidth - 1,
173                     /*plane*/0,
174                     /*planes*/1,
175                     /*rowPitch*/2,
176                     /*colPitch*/2,
177                     /*mapPointsV*/lsmHeight,
178                     /*mapPointsH*/lsmWidth,
179                     /*mapSpacingV*/spacingV,
180                     /*mapSpacingH*/spacingH,
181                     /*mapOriginV*/0,
182                     /*mapOriginH*/0,
183                     /*mapPlanes*/1,
184                     /*mapGains*/greenOddMap);
185    if (err != OK) return err;
186
187    err = addGainMap(/*top*/blueTop,
188                     /*left*/blueLeft,
189                     /*bottom*/activeAreaHeight - 1,
190                     /*right*/activeAreaWidth - 1,
191                     /*plane*/0,
192                     /*planes*/1,
193                     /*rowPitch*/2,
194                     /*colPitch*/2,
195                     /*mapPointsV*/lsmHeight,
196                     /*mapPointsH*/lsmWidth,
197                     /*mapSpacingV*/spacingV,
198                     /*mapSpacingH*/spacingH,
199                     /*mapOriginV*/0,
200                     /*mapOriginH*/0,
201                     /*mapPlanes*/1,
202                     /*mapGains*/blueMap);
203    return err;
204}
205
206status_t OpcodeListBuilder::addGainMap(uint32_t top,
207                                       uint32_t left,
208                                       uint32_t bottom,
209                                       uint32_t right,
210                                       uint32_t plane,
211                                       uint32_t planes,
212                                       uint32_t rowPitch,
213                                       uint32_t colPitch,
214                                       uint32_t mapPointsV,
215                                       uint32_t mapPointsH,
216                                       double mapSpacingV,
217                                       double mapSpacingH,
218                                       double mapOriginV,
219                                       double mapOriginH,
220                                       uint32_t mapPlanes,
221                                       const float* mapGains) {
222
223    uint32_t opcodeId = GAIN_MAP_ID;
224
225    status_t err = mEndianOut.write(&opcodeId, 0, 1);
226    if (err != OK) return err;
227
228    uint8_t version[] = {1, 3, 0, 0};
229    err = mEndianOut.write(version, 0, NELEMS(version));
230    if (err != OK) return err;
231
232    // Do not include optional flag for preview, as this can have a large effect on the output.
233    uint32_t flags = FLAG_OPTIONAL;
234
235    err = mEndianOut.write(&flags, 0, 1);
236    if (err != OK) return err;
237
238    const uint32_t NUMBER_INT_ARGS = 11;
239    const uint32_t NUMBER_DOUBLE_ARGS = 4;
240
241    uint32_t totalSize = NUMBER_INT_ARGS * sizeof(uint32_t) + NUMBER_DOUBLE_ARGS * sizeof(double) +
242            mapPointsV * mapPointsH * mapPlanes * sizeof(float);
243
244    err = mEndianOut.write(&totalSize, 0, 1);
245    if (err != OK) return err;
246
247    // Batch writes as much as possible
248    uint32_t settings1[] = { top,
249                            left,
250                            bottom,
251                            right,
252                            plane,
253                            planes,
254                            rowPitch,
255                            colPitch,
256                            mapPointsV,
257                            mapPointsH };
258
259    err = mEndianOut.write(settings1, 0, NELEMS(settings1));
260    if (err != OK) return err;
261
262    double settings2[] = { mapSpacingV,
263                          mapSpacingH,
264                          mapOriginV,
265                          mapOriginH };
266
267    err = mEndianOut.write(settings2, 0, NELEMS(settings2));
268    if (err != OK) return err;
269
270    err = mEndianOut.write(&mapPlanes, 0, 1);
271    if (err != OK) return err;
272
273    err = mEndianOut.write(mapGains, 0, mapPointsV * mapPointsH * mapPlanes);
274    if (err != OK) return err;
275
276    mCount++;
277
278    return OK;
279}
280
281} /*namespace img_utils*/
282} /*namespace android*/
283