Home | History | Annotate | Download | only in src
      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 
     28 OpcodeListBuilder::OpcodeListBuilder() : mCount(0), mOpList(), mEndianOut(&mOpList, BIG) {
     29     if(mEndianOut.open() != OK) {
     30         ALOGE("%s: Open failed.", __FUNCTION__);
     31     }
     32 }
     33 
     34 OpcodeListBuilder::~OpcodeListBuilder() {
     35     if(mEndianOut.close() != OK) {
     36         ALOGE("%s: Close failed.", __FUNCTION__);
     37     }
     38 }
     39 
     40 size_t OpcodeListBuilder::getSize() const {
     41     return mOpList.getSize() + sizeof(mCount);
     42 }
     43 
     44 uint32_t OpcodeListBuilder::getCount() const {
     45     return mCount;
     46 }
     47 
     48 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 
     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 
    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 
    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 
    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 
    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 
    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 
    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