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     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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