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