Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 30054976 authored by Dichen Zhang's avatar Dichen Zhang Committed by Android (Google) Code Review
Browse files

Merge changes Ic50dd34b,Ib8f5fbef,I058200ca into main

* changes:
  ultrahdr: update jpegencoderhelper to accept uncompressed struct fields
  ultrahdr: correct offset used during look ups
  ultrahdr: minor fixes in encoder and decoder fuzzer
parents 10d3ca60 eca8194f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ void UltraHdrDecFuzzer::process() {
    std::cout << "input buffer size " << jpegImgR.length << std::endl;
    std::cout << "image dimensions " << info.width << " x " << info.width << std::endl;
#endif
    size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_SDR) ? 4 : 8);
    size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4);
    jpegr_uncompressed_struct decodedJpegR;
    auto decodedRaw = std::make_unique<uint8_t[]>(outSize);
    decodedJpegR.data = decodedRaw.get();
+83 −41
Original line number Diff line number Diff line
@@ -23,8 +23,8 @@

// User include files
#include "ultrahdr/gainmapmath.h"
#include "ultrahdr/jpegencoderhelper.h"
#include "ultrahdr/jpegdecoderhelper.h"
#include "ultrahdr/jpegencoderhelper.h"
#include "utils/Log.h"

using namespace android::ultrahdr;
@@ -50,7 +50,7 @@ public:
    UltraHdrEncFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
    void process();
    void fillP010Buffer(uint16_t* data, int width, int height, int stride);
    void fill420Buffer(uint8_t* data, int size);
    void fill420Buffer(uint8_t* data, int width, int height, int stride);

private:
    FuzzedDataProvider mFdp;
@@ -60,11 +60,12 @@ void UltraHdrEncFuzzer::fillP010Buffer(uint16_t* data, int width, int height, in
    uint16_t* tmp = data;
    std::vector<uint16_t> buffer(16);
    for (int i = 0; i < buffer.size(); i++) {
        buffer[i] = mFdp.ConsumeIntegralInRange<int>(0, (1 << 10) - 1);
        buffer[i] = (mFdp.ConsumeIntegralInRange<int>(0, (1 << 10) - 1)) << 6;
    }
    for (int j = 0; j < height; j++) {
        for (int i = 0; i < width; i += buffer.size()) {
            memcpy(data + i, buffer.data(), std::min((int)buffer.size(), (width - i)));
            memcpy(tmp + i, buffer.data(),
                   std::min((int)buffer.size(), (width - i)) * sizeof(*data));
            std::shuffle(buffer.begin(), buffer.end(),
                         std::default_random_engine(std::random_device{}()));
        }
@@ -72,14 +73,19 @@ void UltraHdrEncFuzzer::fillP010Buffer(uint16_t* data, int width, int height, in
    }
}

void UltraHdrEncFuzzer::fill420Buffer(uint8_t* data, int size) {
void UltraHdrEncFuzzer::fill420Buffer(uint8_t* data, int width, int height, int stride) {
    uint8_t* tmp = data;
    std::vector<uint8_t> buffer(16);
    mFdp.ConsumeData(buffer.data(), buffer.size());
    for (int i = 0; i < size; i += buffer.size()) {
        memcpy(data + i, buffer.data(), std::min((int)buffer.size(), (size - i)));
    for (int j = 0; j < height; j++) {
        for (int i = 0; i < width; i += buffer.size()) {
            memcpy(tmp + i, buffer.data(),
                   std::min((int)buffer.size(), (width - i)) * sizeof(*data));
            std::shuffle(buffer.begin(), buffer.end(),
                         std::default_random_engine(std::random_device{}()));
        }
        tmp += stride;
    }
}

void UltraHdrEncFuzzer::process() {
@@ -119,9 +125,10 @@ void UltraHdrEncFuzzer::process() {
        int height = mFdp.ConsumeIntegralInRange<int>(kMinHeight, kMaxHeight);
        height = (height >> 1) << 1;

        std::unique_ptr<uint16_t[]> bufferY = nullptr;
        std::unique_ptr<uint16_t[]> bufferUV = nullptr;
        std::unique_ptr<uint8_t[]> yuv420ImgRaw = nullptr;
        std::unique_ptr<uint16_t[]> bufferYHdr = nullptr;
        std::unique_ptr<uint16_t[]> bufferUVHdr = nullptr;
        std::unique_ptr<uint8_t[]> bufferYSdr = nullptr;
        std::unique_ptr<uint8_t[]> bufferUVSdr = nullptr;
        std::unique_ptr<uint8_t[]> grayImgRaw = nullptr;
        if (muxSwitch != 4) {
            // init p010 image
@@ -135,30 +142,29 @@ void UltraHdrEncFuzzer::process() {
            int bppP010 = 2;
            if (isUVContiguous) {
                size_t p010Size = yStride * height * 3 / 2;
                bufferY = std::make_unique<uint16_t[]>(p010Size);
                p010Img.data = bufferY.get();
                bufferYHdr = std::make_unique<uint16_t[]>(p010Size);
                p010Img.data = bufferYHdr.get();
                p010Img.chroma_data = nullptr;
                p010Img.chroma_stride = 0;
                fillP010Buffer(bufferY.get(), width, height, yStride);
                fillP010Buffer(bufferY.get() + yStride * height, width, height / 2, yStride);
                fillP010Buffer(bufferYHdr.get(), width, height, yStride);
                fillP010Buffer(bufferYHdr.get() + yStride * height, width, height / 2, yStride);
            } else {
                int uvStride = mFdp.ConsumeIntegralInRange<int>(width, width + 128);
                size_t p010YSize = yStride * height;
                bufferY = std::make_unique<uint16_t[]>(p010YSize);
                p010Img.data = bufferY.get();
                fillP010Buffer(bufferY.get(), width, height, yStride);
                bufferYHdr = std::make_unique<uint16_t[]>(p010YSize);
                p010Img.data = bufferYHdr.get();
                fillP010Buffer(bufferYHdr.get(), width, height, yStride);
                size_t p010UVSize = uvStride * p010Img.height / 2;
                bufferUV = std::make_unique<uint16_t[]>(p010UVSize);
                p010Img.chroma_data = bufferUV.get();
                bufferUVHdr = std::make_unique<uint16_t[]>(p010UVSize);
                p010Img.chroma_data = bufferUVHdr.get();
                p010Img.chroma_stride = uvStride;
                fillP010Buffer(bufferUV.get(), width, height / 2, uvStride);
                fillP010Buffer(bufferUVHdr.get(), width, height / 2, uvStride);
            }
        } else {
            int map_width = width / kMapDimensionScaleFactor;
            int map_height = height / kMapDimensionScaleFactor;
            map_width = static_cast<size_t>(floor((map_width + kJpegBlock - 1) / kJpegBlock)) *
                    kJpegBlock;
            map_height = ((map_height + 1) >> 1) << 1;
            size_t map_width = static_cast<size_t>(
                    floor((width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor));
            size_t map_height = static_cast<size_t>(
                    floor((height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor));
            // init 400 image
            grayImg.width = map_width;
            grayImg.height = map_height;
@@ -167,7 +173,7 @@ void UltraHdrEncFuzzer::process() {
            const size_t graySize = map_width * map_height;
            grayImgRaw = std::make_unique<uint8_t[]>(graySize);
            grayImg.data = grayImgRaw.get();
            fill420Buffer(grayImgRaw.get(), graySize);
            fill420Buffer(grayImgRaw.get(), map_width, map_height, map_width);
            grayImg.chroma_data = nullptr;
            grayImg.luma_stride = 0;
            grayImg.chroma_stride = 0;
@@ -175,17 +181,38 @@ void UltraHdrEncFuzzer::process() {

        if (muxSwitch > 0) {
            // init 420 image
            bool isUVContiguous = mFdp.ConsumeBool();
            bool hasYStride = mFdp.ConsumeBool();
            int yStride = hasYStride ? mFdp.ConsumeIntegralInRange<int>(width, width + 128) : width;
            yuv420Img.width = width;
            yuv420Img.height = height;
            yuv420Img.colorGamut = yuv420Cg;

            const size_t yuv420Size = (yuv420Img.width * yuv420Img.height * 3) / 2;
            yuv420ImgRaw = std::make_unique<uint8_t[]>(yuv420Size);
            yuv420Img.data = yuv420ImgRaw.get();
            fill420Buffer(yuv420ImgRaw.get(), yuv420Size);
            yuv420Img.luma_stride = hasYStride ? yStride : 0;
            if (isUVContiguous) {
                size_t yuv420Size = yStride * height * 3 / 2;
                bufferYSdr = std::make_unique<uint8_t[]>(yuv420Size);
                yuv420Img.data = bufferYSdr.get();
                yuv420Img.chroma_data = nullptr;
            yuv420Img.luma_stride = 0;
                yuv420Img.chroma_stride = 0;
                fill420Buffer(bufferYSdr.get(), width, height, yStride);
                fill420Buffer(bufferYSdr.get() + yStride * height, width / 2, height / 2,
                              yStride / 2);
                fill420Buffer(bufferYSdr.get() + yStride * height * 5 / 4, width / 2, height / 2,
                              yStride / 2);
            } else {
                int uvStride = mFdp.ConsumeIntegralInRange<int>(width / 2, width / 2 + 128);
                size_t yuv420YSize = yStride * height;
                bufferYSdr = std::make_unique<uint8_t[]>(yuv420YSize);
                yuv420Img.data = bufferYSdr.get();
                fill420Buffer(bufferYSdr.get(), width, height, yStride);
                size_t yuv420UVSize = uvStride * yuv420Img.height / 2 * 2;
                bufferUVSdr = std::make_unique<uint8_t[]>(yuv420UVSize);
                yuv420Img.chroma_data = bufferYSdr.get();
                yuv420Img.chroma_stride = uvStride;
                fill420Buffer(bufferUVSdr.get(), width / 2, height / 2, uvStride);
                fill420Buffer(bufferUVSdr.get() + uvStride * height / 2, width / 2, height / 2,
                              uvStride);
            }
        }

        // dest
@@ -202,6 +229,8 @@ void UltraHdrEncFuzzer::process() {
        std::cout << "p010 luma stride " << p010Img.luma_stride << std::endl;
        std::cout << "p010 chroma stride " << p010Img.chroma_stride << std::endl;
        std::cout << "420 color gamut " << yuv420Img.colorGamut << std::endl;
        std::cout << "420 luma stride " << yuv420Img.luma_stride << std::endl;
        std::cout << "420 chroma stride " << yuv420Img.chroma_stride << std::endl;
        std::cout << "quality factor " << quality << std::endl;
#endif

@@ -216,8 +245,19 @@ void UltraHdrEncFuzzer::process() {
        } else {
            // compressed img
            JpegEncoderHelper encoder;
            if (encoder.compressImage(yuv420Img.data, yuv420Img.width, yuv420Img.height, quality,
                                      nullptr, 0)) {
            struct jpegr_uncompressed_struct yuv420ImgCopy = yuv420Img;
            if (yuv420ImgCopy.luma_stride == 0) yuv420ImgCopy.luma_stride = yuv420Img.width;
            if (!yuv420ImgCopy.chroma_data) {
                uint8_t* data = reinterpret_cast<uint8_t*>(yuv420Img.data);
                yuv420ImgCopy.chroma_data = data + yuv420Img.luma_stride * yuv420Img.height;
                yuv420ImgCopy.chroma_stride = yuv420Img.luma_stride >> 1;
            }

            if (encoder.compressImage(reinterpret_cast<uint8_t*>(yuv420ImgCopy.data),
                                      reinterpret_cast<uint8_t*>(yuv420ImgCopy.chroma_data),
                                      yuv420ImgCopy.width, yuv420ImgCopy.height,
                                      yuv420ImgCopy.luma_stride, yuv420ImgCopy.chroma_stride,
                                      quality, nullptr, 0)) {
                jpegImg.length = encoder.getCompressedImageSize();
                jpegImg.maxLength = jpegImg.length;
                jpegImg.data = encoder.getCompressedImagePtr();
@@ -232,8 +272,9 @@ void UltraHdrEncFuzzer::process() {
                } else if (muxSwitch == 4) { // api 4
                    jpegImgR.length = 0;
                    JpegEncoderHelper gainMapEncoder;
                    if (gainMapEncoder.compressImage(grayImg.data, grayImg.width, grayImg.height,
                                                     quality, nullptr, 0, true)) {
                    if (gainMapEncoder.compressImage(reinterpret_cast<uint8_t*>(grayImg.data),
                                                     nullptr, grayImg.width, grayImg.height,
                                                     grayImg.width, 0, quality, nullptr, 0)) {
                        jpegGainMap.length = gainMapEncoder.getCompressedImageSize();
                        jpegGainMap.maxLength = jpegImg.length;
                        jpegGainMap.data = gainMapEncoder.getCompressedImagePtr();
@@ -264,7 +305,8 @@ void UltraHdrEncFuzzer::process() {
            jpegr_info_struct info{0, 0, &iccData, &exifData};
            status = jpegHdr.getJPEGRInfo(&jpegImgR, &info);
            if (status == android::OK) {
                size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_SDR) ? 4 : 8);
                size_t outSize =
                        info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4);
                jpegr_uncompressed_struct decodedJpegR;
                auto decodedRaw = std::make_unique<uint8_t[]>(outSize);
                decodedJpegR.data = decodedRaw.get();
+5 −5
Original line number Diff line number Diff line
@@ -168,7 +168,7 @@ Color srgbInvOetf(Color e_gamma) {

// See IEC 61966-2-1, Equations F.5 and F.6.
float srgbInvOetfLUT(float e_gamma) {
  uint32_t value = static_cast<uint32_t>(e_gamma * kSrgbInvOETFNumEntries);
  uint32_t value = static_cast<uint32_t>(e_gamma * (kSrgbInvOETFNumEntries - 1) + 0.5);
  //TODO() : Remove once conversion modules have appropriate clamping in place
  value = CLIP3(value, 0, kSrgbInvOETFNumEntries - 1);
  return kSrgbInvOETF[value];
@@ -288,7 +288,7 @@ Color hlgOetf(Color e) {
}

float hlgOetfLUT(float e) {
  uint32_t value = static_cast<uint32_t>(e * kHlgOETFNumEntries);
  uint32_t value = static_cast<uint32_t>(e * (kHlgOETFNumEntries - 1) + 0.5);
  //TODO() : Remove once conversion modules have appropriate clamping in place
  value = CLIP3(value, 0, kHlgOETFNumEntries - 1);

@@ -315,7 +315,7 @@ Color hlgInvOetf(Color e_gamma) {
}

float hlgInvOetfLUT(float e_gamma) {
  uint32_t value = static_cast<uint32_t>(e_gamma * kHlgInvOETFNumEntries);
  uint32_t value = static_cast<uint32_t>(e_gamma * (kHlgInvOETFNumEntries - 1) + 0.5);
  //TODO() : Remove once conversion modules have appropriate clamping in place
  value = CLIP3(value, 0, kHlgInvOETFNumEntries - 1);

@@ -344,7 +344,7 @@ Color pqOetf(Color e) {
}

float pqOetfLUT(float e) {
  uint32_t value = static_cast<uint32_t>(e * kPqOETFNumEntries);
  uint32_t value = static_cast<uint32_t>(e * (kPqOETFNumEntries - 1) + 0.5);
  //TODO() : Remove once conversion modules have appropriate clamping in place
  value = CLIP3(value, 0, kPqOETFNumEntries - 1);

@@ -376,7 +376,7 @@ Color pqInvOetf(Color e_gamma) {
}

float pqInvOetfLUT(float e_gamma) {
  uint32_t value = static_cast<uint32_t>(e_gamma * kPqInvOETFNumEntries);
  uint32_t value = static_cast<uint32_t>(e_gamma * (kPqInvOETFNumEntries - 1) + 0.5);
  //TODO() : Remove once conversion modules have appropriate clamping in place
  value = CLIP3(value, 0, kPqInvOETFNumEntries - 1);

+1 −1
Original line number Diff line number Diff line
@@ -172,7 +172,7 @@ struct GainLUT {
  }

  float getGainFactor(float gain) {
    uint32_t idx = static_cast<uint32_t>(gain * (kGainFactorNumEntries - 1));
    uint32_t idx = static_cast<uint32_t>(gain * (kGainFactorNumEntries - 1) + 0.5);
    //TODO() : Remove once conversion modules have appropriate clamping in place
    idx = CLIP3(idx, 0, kGainFactorNumEntries - 1);
    return mGainTable[idx];
+13 −8
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

// We must include cstdio before jpeglib.h. It is a requirement of libjpeg.
#include <cstdio>
#include <vector>

extern "C" {
#include <jerror.h>
@@ -26,10 +27,11 @@ extern "C" {
}

#include <utils/Errors.h>
#include <vector>

namespace android::ultrahdr {

#define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m))

/*
 * Encapsulates a converter from raw image (YUV420planer or grey-scale) to JPEG format.
 * This class is not thread-safe.
@@ -46,8 +48,9 @@ public:
     * ICC segment which will be added to the compressed image.
     * Returns false if errors occur during compression.
     */
    bool compressImage(const void* image, int width, int height, int quality,
                       const void* iccBuffer, unsigned int iccSize, bool isSingleChannel = false);
    bool compressImage(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, int height,
                       int lumaStride, int chromaStride, int quality, const void* iccBuffer,
                       unsigned int iccSize);

    /*
     * Returns the compressed JPEG buffer pointer. This method must be called only after calling
@@ -66,6 +69,7 @@ public:
     * We must pass at least 16 scanlines according to libjpeg documentation.
     */
    static const int kCompressBatchSize = 16;

private:
    // initDestination(), emptyOutputBuffer() and emptyOutputBuffer() are callback functions to be
    // passed into jpeg library.
@@ -75,15 +79,16 @@ private:
    static void outputErrorMessage(j_common_ptr cinfo);

    // Returns false if errors occur.
    bool encode(const void* inYuv, int width, int height, int jpegQuality,
                const void* iccBuffer, unsigned int iccSize, bool isSingleChannel);
    bool encode(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, int height,
                int lumaStride, int chromaStride, int quality, const void* iccBuffer,
                unsigned int iccSize);
    void setJpegDestination(jpeg_compress_struct* cinfo);
    void setJpegCompressStruct(int width, int height, int quality, jpeg_compress_struct* cinfo,
                               bool isSingleChannel);
    // Returns false if errors occur.
    bool compress(jpeg_compress_struct* cinfo, const uint8_t* image, bool isSingleChannel);
    bool compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yuv);
    bool compressSingleChannel(jpeg_compress_struct* cinfo, const uint8_t* image);
    bool compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, const uint8_t* uvBuffer,
                     int lumaStride, int chromaStride);
    bool compressY(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, int lumaStride);

    // The block size for encoded jpeg image buffer.
    static const int kBlockSize = 16384;
Loading