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

Commit 0202c125 authored by Ram Mohan's avatar Ram Mohan Committed by Dichen Zhang
Browse files

ultrahdr: updates to jpegr impl - 2

- clang-format the code to a common guideline
- test resources are automatically pushed by pusher
- minor cleanup

Bug: 294218453
Test: atest ultrahdr_unit_test

Change-Id: I917e9385f2a4b92add8667248a88789b5332da76
parent 8731ebd2
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ extern "C" {
#include <utils/Errors.h>
#include <vector>

// constraint on max width and max height is only due to device alloc constraints
// Can tune these values basing on the target device
static const int kMaxWidth = 8192;
static const int kMaxHeight = 8192;

@@ -94,9 +96,8 @@ public:
    /*
     * Decompresses metadata of the image. All vectors are owned by the caller.
     */
    bool getCompressedImageParameters(const void* image, int length,
                                      size_t* pWidth, size_t* pHeight,
                                      std::vector<uint8_t>* iccData,
    bool getCompressedImageParameters(const void* image, int length, size_t* pWidth,
                                      size_t* pHeight, std::vector<uint8_t>* iccData,
                                      std::vector<uint8_t>* exifData);

private:
+63 −95
Original line number Diff line number Diff line
@@ -76,8 +76,8 @@ static void jpegr_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {

static void jpegr_term_source(j_decompress_ptr /*cinfo*/) {}

jpegr_source_mgr::jpegr_source_mgr(const uint8_t* ptr, int len) :
        mBufferPtr(ptr), mBufferLength(len) {
jpegr_source_mgr::jpegr_source_mgr(const uint8_t* ptr, int len)
      : mBufferPtr(ptr), mBufferLength(len) {
    init_source = jpegr_init_source;
    fill_input_buffer = jpegr_fill_input_buffer;
    skip_input_data = jpegr_skip_input_data;
@@ -92,25 +92,18 @@ static void jpegrerror_exit(j_common_ptr cinfo) {
    longjmp(err->setjmp_buffer, 1);
}

JpegDecoderHelper::JpegDecoderHelper() {
}
JpegDecoderHelper::JpegDecoderHelper() {}

JpegDecoderHelper::~JpegDecoderHelper() {
}
JpegDecoderHelper::~JpegDecoderHelper() {}

bool JpegDecoderHelper::decompressImage(const void* image, int length, bool decodeToRGBA) {
    if (image == nullptr || length <= 0) {
        ALOGE("Image size can not be handled: %d", length);
        return false;
    }

    mResultBuffer.clear();
    mXMPBuffer.clear();
    if (!decode(image, length, decodeToRGBA)) {
        return false;
    }

    return true;
    return decode(image, length, decodeToRGBA);
}

void* JpegDecoderHelper::getDecompressedImagePtr() {
@@ -154,26 +147,28 @@ size_t JpegDecoderHelper::getDecompressedImageHeight() {
}

bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) {
    bool status = true;
    jpeg_decompress_struct cinfo;
    jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
    jpegrerror_mgr myerr;
    bool status = true;

    cinfo.err = jpeg_std_error(&myerr.pub);
    myerr.pub.error_exit = jpegrerror_exit;

    if (setjmp(myerr.setjmp_buffer)) {
        jpeg_destroy_decompress(&cinfo);
        return false;
    }

    jpeg_create_decompress(&cinfo);

    jpeg_save_markers(&cinfo, kAPP0Marker, 0xFFFF);
    jpeg_save_markers(&cinfo, kAPP1Marker, 0xFFFF);
    jpeg_save_markers(&cinfo, kAPP2Marker, 0xFFFF);

    jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
    cinfo.src = &mgr;
    jpeg_read_header(&cinfo, TRUE);
    if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
        jpeg_destroy_decompress(&cinfo);
        return false;
    }

    // Save XMP data, EXIF data, and ICC data.
    // Here we only handle the first XMP / EXIF / ICC package.
@@ -184,31 +179,24 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA)
    bool xmpAppears = false;
    bool iccAppears = false;
    for (jpeg_marker_struct* marker = cinfo.marker_list;
         marker && !(exifAppears && xmpAppears && iccAppears);
         marker = marker->next) {

         marker && !(exifAppears && xmpAppears && iccAppears); marker = marker->next) {
        if (marker->marker != kAPP1Marker && marker->marker != kAPP2Marker) {
            continue;
        }
        const unsigned int len = marker->data_length;
        if (!xmpAppears &&
            len > kXmpNameSpace.size() &&
            !strncmp(reinterpret_cast<const char*>(marker->data),
                     kXmpNameSpace.c_str(),
        if (!xmpAppears && len > kXmpNameSpace.size() &&
            !strncmp(reinterpret_cast<const char*>(marker->data), kXmpNameSpace.c_str(),
                     kXmpNameSpace.size())) {
            mXMPBuffer.resize(len + 1, 0);
            memcpy(static_cast<void*>(mXMPBuffer.data()), marker->data, len);
            xmpAppears = true;
        } else if (!exifAppears &&
                   len > kExifIdCode.size() &&
                   !strncmp(reinterpret_cast<const char*>(marker->data),
                            kExifIdCode.c_str(),
        } else if (!exifAppears && len > kExifIdCode.size() &&
                   !strncmp(reinterpret_cast<const char*>(marker->data), kExifIdCode.c_str(),
                            kExifIdCode.size())) {
            mEXIFBuffer.resize(len, 0);
            memcpy(static_cast<void*>(mEXIFBuffer.data()), marker->data, len);
            exifAppears = true;
        } else if (!iccAppears &&
                   len > sizeof(kICCSig) &&
        } else if (!iccAppears && len > sizeof(kICCSig) &&
                   !memcmp(marker->data, kICCSig, sizeof(kICCSig))) {
            mICCBuffer.resize(len, 0);
            memcpy(static_cast<void*>(mICCBuffer.data()), marker->data, len);
@@ -216,16 +204,13 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA)
        }
    }

    if (cinfo.image_width > kMaxWidth || cinfo.image_height > kMaxHeight) {
        // constraint on max width and max height is only due to alloc constraints
        // tune these values basing on the target device
    mWidth = cinfo.image_width;
    mHeight = cinfo.image_height;
    if (mWidth > kMaxWidth || mHeight > kMaxHeight) {
        status = false;
        goto CleanUp;
    }

    mWidth = cinfo.image_width;
    mHeight = cinfo.image_height;

    if (decodeToRGBA) {
        // The primary image is expected to be yuv420 sampling
        if (cinfo.jpeg_color_space != JCS_YCbCr) {
@@ -233,12 +218,9 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA)
            ALOGE("%s: decodeToRGBA unexpected jpeg color space ", __func__);
            goto CleanUp;
        }
            if (cinfo.comp_info[0].h_samp_factor != 2 ||
                    cinfo.comp_info[1].h_samp_factor != 1 ||
                    cinfo.comp_info[2].h_samp_factor != 1 ||
                    cinfo.comp_info[0].v_samp_factor != 2 ||
                    cinfo.comp_info[1].v_samp_factor != 1 ||
                    cinfo.comp_info[2].v_samp_factor != 1 ) {
        if (cinfo.comp_info[0].h_samp_factor != 2 || cinfo.comp_info[0].v_samp_factor != 2 ||
            cinfo.comp_info[1].h_samp_factor != 1 || cinfo.comp_info[1].v_samp_factor != 1 ||
            cinfo.comp_info[2].h_samp_factor != 1 || cinfo.comp_info[2].v_samp_factor != 1) {
            status = false;
            ALOGE("%s: decodeToRGBA unexpected primary image sub-sampling", __func__);
            goto CleanUp;
@@ -248,12 +230,9 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA)
        cinfo.out_color_space = JCS_EXT_RGBA;
    } else {
        if (cinfo.jpeg_color_space == JCS_YCbCr) {
            if (cinfo.comp_info[0].h_samp_factor != 2 ||
                cinfo.comp_info[1].h_samp_factor != 1 ||
                cinfo.comp_info[2].h_samp_factor != 1 ||
                cinfo.comp_info[0].v_samp_factor != 2 ||
                cinfo.comp_info[1].v_samp_factor != 1 ||
                cinfo.comp_info[2].v_samp_factor != 1) {
            if (cinfo.comp_info[0].h_samp_factor != 2 || cinfo.comp_info[0].v_samp_factor != 2 ||
                cinfo.comp_info[1].h_samp_factor != 1 || cinfo.comp_info[1].v_samp_factor != 1 ||
                cinfo.comp_info[2].h_samp_factor != 1 || cinfo.comp_info[2].v_samp_factor != 1) {
                status = false;
                ALOGE("%s: decoding to YUV only supports 4:2:0 subsampling", __func__);
                goto CleanUp;
@@ -271,9 +250,7 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA)
    }

    cinfo.dct_method = JDCT_ISLOW;

    jpeg_start_decompress(&cinfo);

    if (!decompress(&cinfo, static_cast<const uint8_t*>(mResultBuffer.data()),
                    cinfo.jpeg_color_space == JCS_GRAYSCALE)) {
        status = false;
@@ -289,24 +266,19 @@ CleanUp:

bool JpegDecoderHelper::decompress(jpeg_decompress_struct* cinfo, const uint8_t* dest,
                                   bool isSingleChannel) {
    if (isSingleChannel) {
        return decompressSingleChannel(cinfo, dest);
    }
    if (cinfo->out_color_space == JCS_EXT_RGBA)
        return decompressRGBA(cinfo, dest);
    else
        return decompressYUV(cinfo, dest);
    return isSingleChannel
            ? decompressSingleChannel(cinfo, dest)
            : ((cinfo->out_color_space == JCS_EXT_RGBA) ? decompressRGBA(cinfo, dest)
                                                        : decompressYUV(cinfo, dest));
}

bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int length,
                              size_t *pWidth, size_t *pHeight,
                              std::vector<uint8_t> *iccData , std::vector<uint8_t> *exifData) {
bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int length, size_t* pWidth,
                                                     size_t* pHeight, std::vector<uint8_t>* iccData,
                                                     std::vector<uint8_t>* exifData) {
    jpeg_decompress_struct cinfo;
    jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
    jpegrerror_mgr myerr;
    cinfo.err = jpeg_std_error(&myerr.pub);
    myerr.pub.error_exit = jpegrerror_exit;

    if (setjmp(myerr.setjmp_buffer)) {
        jpeg_destroy_decompress(&cinfo);
        return false;
@@ -316,6 +288,7 @@ bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int leng
    jpeg_save_markers(&cinfo, kAPP1Marker, 0xFFFF);
    jpeg_save_markers(&cinfo, kAPP2Marker, 0xFFFF);

    jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
    cinfo.src = &mgr;
    if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
        jpeg_destroy_decompress(&cinfo);
@@ -330,8 +303,7 @@ bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int leng
    }

    if (iccData != nullptr) {
        for (jpeg_marker_struct* marker = cinfo.marker_list; marker;
             marker = marker->next) {
        for (jpeg_marker_struct* marker = cinfo.marker_list; marker; marker = marker->next) {
            if (marker->marker != kAPP2Marker) {
                continue;
            }
@@ -368,18 +340,13 @@ bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int leng
}

bool JpegDecoderHelper::decompressRGBA(jpeg_decompress_struct* cinfo, const uint8_t* dest) {
    JSAMPLE* decodeDst = (JSAMPLE*) dest;
    uint32_t lines = 0;
    // TODO: use batches for more effectiveness
    while (lines < cinfo->image_height) {
        uint32_t ret = jpeg_read_scanlines(cinfo, &decodeDst, 1);
        if (ret == 0) {
            break;
        }
        decodeDst += cinfo->image_width * 4;
        lines++;
    JSAMPLE* out = (JSAMPLE*)dest;

    while (cinfo->output_scanline < cinfo->image_height) {
        if (1 != jpeg_read_scanlines(cinfo, &out, 1)) return false;
        out += cinfo->image_width * 4;
    }
    return lines == cinfo->image_height;
    return true;
}

bool JpegDecoderHelper::decompressYUV(jpeg_decompress_struct* cinfo, const uint8_t* dest) {
@@ -462,7 +429,8 @@ bool JpegDecoderHelper::decompressYUV(jpeg_decompress_struct* cinfo, const uint8
    return true;
}

bool JpegDecoderHelper::decompressSingleChannel(jpeg_decompress_struct* cinfo, const uint8_t* dest) {
bool JpegDecoderHelper::decompressSingleChannel(jpeg_decompress_struct* cinfo,
                                                const uint8_t* dest) {
    JSAMPROW y[kCompressBatchSize];
    JSAMPARRAY planes[1]{y};

@@ -510,4 +478,4 @@ bool JpegDecoderHelper::decompressSingleChannel(jpeg_decompress_struct* cinfo, c
    return true;
}

} // namespace ultrahdr
} // namespace android::ultrahdr
+4 −33
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ cc_test {
        "gainmapmath_test.cpp",
        "icchelper_test.cpp",
        "jpegr_test.cpp",
        "jpegencoderhelper_test.cpp",
        "jpegdecoderhelper_test.cpp",
    ],
    shared_libs: [
        "libimage_io",
@@ -42,38 +44,7 @@ cc_test {
        "libultrahdr",
        "libutils",
    ],
}

cc_test {
    name: "jpegencoderhelper_test",
    test_suites: ["device-tests"],
    srcs: [
        "jpegencoderhelper_test.cpp",
    ],
    shared_libs: [
        "libjpeg",
        "liblog",
    ],
    static_libs: [
        "libgtest",
        "libjpegencoder",
    ],
}

cc_test {
    name: "jpegdecoderhelper_test",
    test_suites: ["device-tests"],
    srcs: [
        "jpegdecoderhelper_test.cpp",
    ],
    shared_libs: [
        "libjpeg",
        "liblog",
    ],
    static_libs: [
        "libgtest",
        "libjpegdecoder",
        "libultrahdr",
        "libutils",
    data: [
        "./data/*.*",
    ],
}
+26 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the"License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an"AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<configuration description="Unit test configuration for ultrahdr_unit_test">
    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
        <option name="cleanup" value="true" />
        <option name="push-file" key="ultrahdr_unit_test" value="/data/local/tmp/ultrahdr_unit_test" />
        <option name="push" value="data/*->/data/local/tmp/" />
    </target_preparer>
    <test class="com.android.tradefed.testtype.GTest" >
        <option name="native-test-device-path" value="/data/local/tmp" />
        <option name="module-name" value="ultrahdr_unit_test" />
    </test>
</configuration>
+10 −10
Original line number Diff line number Diff line
@@ -14,9 +14,9 @@
 * limitations under the License.
 */

#include <ultrahdr/jpegdecoderhelper.h>
#include <ultrahdr/icc.h>
#include <gtest/gtest.h>
#include <ultrahdr/icc.h>
#include <ultrahdr/jpegdecoderhelper.h>
#include <utils/Log.h>

#include <fcntl.h>
@@ -24,13 +24,13 @@
namespace android::ultrahdr {

// No ICC or EXIF
#define YUV_IMAGE "/sdcard/Documents/minnie-320x240-yuv.jpg"
#define YUV_IMAGE "/data/local/tmp/minnie-320x240-yuv.jpg"
#define YUV_IMAGE_SIZE 20193
// Has ICC and EXIF
#define YUV_ICC_IMAGE "/sdcard/Documents/minnie-320x240-yuv-icc.jpg"
#define YUV_ICC_IMAGE "/data/local/tmp/minnie-320x240-yuv-icc.jpg"
#define YUV_ICC_IMAGE_SIZE 34266
// No ICC or EXIF
#define GREY_IMAGE "/sdcard/Documents/minnie-320x240-y.jpg"
#define GREY_IMAGE "/data/local/tmp/minnie-320x240-y.jpg"
#define GREY_IMAGE_SIZE 20193

#define IMAGE_WIDTH 320
@@ -44,6 +44,7 @@ public:
    };
    JpegDecoderHelperTest();
    ~JpegDecoderHelperTest();

protected:
    virtual void SetUp();
    virtual void TearDown();
@@ -127,8 +128,8 @@ TEST_F(JpegDecoderHelperTest, getCompressedImageParameters) {
    std::vector<uint8_t> icc, exif;

    JpegDecoderHelper decoder;
    EXPECT_TRUE(decoder.getCompressedImageParameters(mYuvImage.buffer.get(), mYuvImage.size,
                                                     &width, &height, &icc, &exif));
    EXPECT_TRUE(decoder.getCompressedImageParameters(mYuvImage.buffer.get(), mYuvImage.size, &width,
                                                     &height, &icc, &exif));

    EXPECT_EQ(width, IMAGE_WIDTH);
    EXPECT_EQ(height, IMAGE_HEIGHT);
@@ -149,8 +150,7 @@ TEST_F(JpegDecoderHelperTest, getCompressedImageParametersIcc) {
    EXPECT_GT(icc.size(), 0);
    EXPECT_GT(exif.size(), 0);

    EXPECT_EQ(IccHelper::readIccColorGamut(icc.data(), icc.size()),
              ULTRAHDR_COLORGAMUT_BT709);
    EXPECT_EQ(IccHelper::readIccColorGamut(icc.data(), icc.size()), ULTRAHDR_COLORGAMUT_BT709);
}

} // namespace android::ultrahdr
Loading