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