Home | History | Annotate | Download | only in libhdrplusclient
      1 /*
      2  * Copyright 2016 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 //#define LOG_NDEBUG 0
     17 #define LOG_TAG "HdrPlusClientUtils"
     18 #include <log/log.h>
     19 
     20 #include <fstream>
     21 #include <inttypes.h>
     22 #include <system/graphics.h>
     23 
     24 #include "HdrPlusClientUtils.h"
     25 
     26 namespace android {
     27 namespace hdrplus_client_utils {
     28 
     29 // Get the RGB values of the pixel at (x, y).
     30 static status_t getRgb(uint8_t *r, uint8_t *g, uint8_t* b, uint32_t x, uint32_t y,
     31         const pbcamera::StreamConfiguration &streamConfig,
     32         const pbcamera::StreamBuffer &buffer) {
     33     switch (streamConfig.image.format) {
     34         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
     35         {
     36             // Check the stream configuration has two planes.
     37             if (streamConfig.image.planes.size() != 2) {
     38                 ALOGE("%s: NV21 should have 2 planes but it has %zu", __FUNCTION__,
     39                         streamConfig.image.planes.size());
     40                 return BAD_VALUE;
     41             }
     42 
     43             // Find the indices of Y, V, and U in the buffer.
     44             uint32_t yIndex = y * streamConfig.image.planes[0].stride + x;
     45             uint32_t vIndex = streamConfig.image.planes[0].scanline *
     46                               streamConfig.image.planes[0].stride +
     47                               (y / 2) * streamConfig.image.planes[1].stride + (x & ~0x1);
     48             uint32_t uIndex = vIndex + 1;
     49 
     50             // Convert YUV to RGB.
     51             int32_t yc = ((uint8_t*)buffer.data)[yIndex];
     52             int32_t vc = ((uint8_t*)buffer.data)[vIndex] - 128;
     53             int32_t uc = ((uint8_t*)buffer.data)[uIndex] - 128;
     54             *r = std::min(std::max(yc + 0.003036f * uc + 1.399457f * vc, 0.0f), 255.0f);
     55             *g = std::min(std::max(yc - 0.344228f * uc - 0.717202f * vc, 0.0f), 255.0f);
     56             *b = std::min(std::max(yc + 1.772431f * uc - 0.006137f * vc, 0.0f), 255.0f);
     57             return OK;
     58         }
     59         case HAL_PIXEL_FORMAT_RGB_888:
     60         {
     61             // Check the stream configuration has 1 plane.
     62             if (streamConfig.image.planes.size() != 1) {
     63                 ALOGE("%s: RGB_888 should have 1 plane but it has %zu", __FUNCTION__,
     64                         streamConfig.image.planes.size());
     65                 return BAD_VALUE;
     66             }
     67 
     68             uint32_t offset = y * streamConfig.image.planes[0].stride + x * 3;
     69             *r = ((uint8_t*)buffer.data)[offset];
     70             *g = ((uint8_t*)buffer.data)[offset + 1];
     71             *b = ((uint8_t*)buffer.data)[offset + 2];
     72             return OK;
     73         }
     74         default:
     75             ALOGE("%s: Format %d is not supported.", __FUNCTION__, streamConfig.image.format);
     76             return BAD_VALUE;
     77     }
     78 }
     79 
     80 status_t writePpm(const std::string &filename, const pbcamera::StreamConfiguration &streamConfig,
     81         const pbcamera::StreamBuffer &buffer) {
     82     if (streamConfig.image.format != HAL_PIXEL_FORMAT_YCrCb_420_SP &&
     83             streamConfig.image.format != HAL_PIXEL_FORMAT_RGB_888) {
     84         ALOGE("%s: format 0x%x is not supported.", __FUNCTION__, streamConfig.image.format);
     85         return BAD_VALUE;
     86     }
     87 
     88     std::ofstream outfile(filename, std::ios::binary);
     89     if (!outfile.is_open()) {
     90         ALOGE("%s: Opening file (%s) failed.", __FUNCTION__, filename.data());
     91         return NO_INIT;
     92     }
     93 
     94     uint32_t width = streamConfig.image.width;
     95     uint32_t height = streamConfig.image.height;
     96 
     97     // Write headers of the ppm file.
     98     outfile << "P6";
     99     outfile << " " << std::to_string(width) << " " << std::to_string(height) << " 255 ";
    100 
    101     // Write RGB values of the image.
    102     uint8_t r, g, b;
    103     for (uint32_t y = 0; y < height; y++) {
    104         for (uint32_t x = 0; x < width; x++) {
    105             status_t res = getRgb(&r, &g, &b, x, y, streamConfig, buffer);
    106             if (res != OK) {
    107                 ALOGE("%s: Getting RGB failed: %s (%d).", __FUNCTION__, strerror(-res), res);
    108                 return res;
    109             }
    110             outfile << r << g << b;
    111         }
    112     }
    113 
    114     ALOGD("%s: Saved file: %s", __FUNCTION__, filename.data());
    115 
    116     outfile.close();
    117     return OK;
    118 }
    119 
    120 status_t comparePpm(const std::string &filename, const pbcamera::StreamConfiguration &streamConfig,
    121         const pbcamera::StreamBuffer &buffer, float *diffRatio) {
    122     if (streamConfig.image.format != HAL_PIXEL_FORMAT_YCrCb_420_SP) {
    123         ALOGE("%s: format 0x%x is not supported.", __FUNCTION__, streamConfig.image.format);
    124         return BAD_VALUE;
    125     }
    126 
    127     std::ifstream ifile(filename, std::ios::binary);
    128     if (!ifile.is_open()) {
    129         ALOGE("%s: Opening file (%s) failed.", __FUNCTION__, filename.data());
    130         return NO_INIT;
    131     }
    132 
    133     std::string s;
    134 
    135     // Read headers of the ppm file.
    136     ifile >> s;
    137     if (s != "P6") {
    138         ALOGE("%s: Invalid PPM file header: %s", __FUNCTION__, s.c_str());
    139         return BAD_VALUE;
    140     }
    141 
    142     // Read width and height.
    143     ifile >> s;
    144     uint32_t width = std::stoul(s);
    145 
    146     ifile >> s;
    147     uint32_t height = std::stoul(s);
    148 
    149     if (width != streamConfig.image.width || height != streamConfig.image.height) {
    150         ALOGE("%s: Image resolution doesn't match. image %dx%d ppm %dx%d",
    151                 __FUNCTION__, streamConfig.image.width, streamConfig.image.height,
    152                 width, height);
    153         return BAD_VALUE;
    154     }
    155 
    156     ifile >> s;
    157     if (s != "255") {
    158         ALOGE("%s: Expecting 255 but got %s", __FUNCTION__, s.c_str());
    159         return BAD_VALUE;
    160     }
    161 
    162     char c;
    163 
    164     // Get a space
    165     ifile.get(c);
    166 
    167     // Now the RGB values start.
    168     uint8_t r, g, b;
    169     uint64_t diff = 0;
    170 
    171     for (uint32_t y = 0; y < height; y++) {
    172         for (uint32_t x = 0; x < width; x++) {
    173             status_t res = getRgb(&r, &g, &b, x, y, streamConfig, buffer);
    174             if (res != OK) {
    175                 ALOGE("%s: Getting RGB failed: %s (%d).", __FUNCTION__, strerror(-res), res);
    176                 return res;
    177             }
    178 
    179             // Get r, g, b from golden image and accumulate the differences.
    180             ifile.get(c);
    181             diff += abs(static_cast<int32_t>(c) - r);
    182             ifile.get(c);
    183             diff += abs(static_cast<int32_t>(c) - g);
    184             ifile.get(c);
    185             diff += abs(static_cast<int32_t>(c) - b);
    186         }
    187     }
    188 
    189     if (diffRatio != nullptr) {
    190         *diffRatio = diff / (static_cast<float>(width) * height * 3 * 256);
    191     }
    192 
    193     return OK;
    194 }
    195 
    196 } // hdrplus_client_utils
    197 } // namespace android
    198