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

Commit 1dcc4429 authored by Fyodor Kyslov's avatar Fyodor Kyslov
Browse files

JPEGR Decoder. Inital implementation

* Implements JPEGR Decoding
* Doesn't implement XMP data parsing
* Implements retrieval of image data

Bug: b/252835416
Test: build

Change-Id: I62c7c323842b8d87866c43e85c1d7238e5b9b0d5
parent 83affa69
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ cc_library_static {
    srcs: [
        "recoverymap.cpp",
        "recoverymapmath.cpp",
        "recoverymaputils.cpp",
    ],

    shared_libs: [
+18 −0
Original line number Diff line number Diff line
@@ -61,6 +61,21 @@ public:
     * decompressImage().
     */
    size_t getDecompressedImageHeight();
    /*
     * Returns the XMP data from the image.
     */
    void* getXMPPtr();
    /*
     * Returns the decompressed XMP buffer size. This method must be called only after
     * calling decompressImage().
     */
    size_t getXMPSize();

    bool getCompressedImageParameters(const void* image, int length,
                              size_t* pWidth, size_t* pHeight,
                              std::vector<uint8_t>* &iccData,
                              std::vector<uint8_t>* &exifData);

private:
    bool decode(const void* image, int length);
    // Returns false if errors occur.
@@ -72,6 +87,9 @@ private:
    static const int kCompressBatchSize = 16;
    // The buffer that holds the decompressed result.
    std::vector<JOCTET> mResultBuffer;
    // The buffer that holds XMP Data.
    std::vector<JOCTET> mXMPBuffer;

    // Resolution of the decompressed image.
    size_t mWidth;
    size_t mHeight;
+33 −5
Original line number Diff line number Diff line
@@ -34,6 +34,13 @@ typedef enum {
  JPEGR_TF_PQ = 1,
} jpegr_transfer_function;

struct jpegr_info_struct {
    size_t width;
    size_t height;
    std::vector<uint8_t>* iccData;
    std::vector<uint8_t>* exifData;
};

/*
 * Holds information for uncompressed image or recovery map.
 */
@@ -117,6 +124,7 @@ typedef struct jpegr_uncompressed_struct* jr_uncompressed_ptr;
typedef struct jpegr_compressed_struct* jr_compressed_ptr;
typedef struct jpegr_exif_struct* jr_exif_ptr;
typedef struct jpegr_metadata* jr_metadata_ptr;
typedef struct jpegr_info_struct* jr_info_ptr;

class RecoveryMap {
public:
@@ -200,8 +208,19 @@ public:
     */
    status_t decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
                         jr_uncompressed_ptr dest,
                         jr_exif_ptr exif,
                         bool request_sdr);
                         jr_exif_ptr exif = nullptr,
                         bool request_sdr = false);

    /*
    * Gets Info from JPEGR file without decoding it.
    *
    * The output is filled jpegr_info structure
    * @param compressed_jpegr_image compressed JPEGR image
    * @param jpegr_info pointer to output JPEGR info
    * @return NO_ERROR if JPEGR parsing succeeds, error code otherwise
    */
    status_t getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image,
                          jr_info_ptr jpegr_info);
private:
    /*
     * This method is called in the decoding pipeline. It will decode the recovery map.
@@ -259,18 +278,27 @@ private:
                              jr_metadata_ptr metadata,
                              jr_uncompressed_ptr dest);

    /*
     * This methoud is called to separate primary image and recovery map image from JPEGR
     *
     * @param compressed_jpegr_image compressed JPEGR image
     * @param primary_image destination of primary image
     * @param recovery_map destination of compressed recovery map
     * @return NO_ERROR if calculation succeeds, error code if error occurs.
    */
    status_t extractPrimaryImageAndRecoveryMap(jr_compressed_ptr compressed_jpegr_image,
                                               jr_compressed_ptr primary_image,
                                               jr_compressed_ptr recovery_map);
    /*
     * This method is called in the decoding pipeline. It will read XMP metadata to find the start
     * position of the compressed recovery map, and will extract the compressed recovery map.
     *
     * @param compressed_jpegr_image compressed JPEGR image
     * @param dest destination of compressed recovery map
     * @param metadata destination of the recovery map metadata
     * @return NO_ERROR if calculation succeeds, error code if error occurs.
     */
    status_t extractRecoveryMap(jr_compressed_ptr compressed_jpegr_image,
                                jr_compressed_ptr dest,
                                jr_metadata_ptr metadata);
                                jr_compressed_ptr dest);

    /*
     * This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image
+40 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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.
 */

#ifndef ANDROID_JPEGRECOVERYMAP_RECOVERYMAPUTILS_H
#define ANDROID_JPEGRECOVERYMAP_RECOVERYMAPUTILS_H

#include <stdint.h>
#include <cstdio>


namespace android::recoverymap {

struct jpegr_metadata;

/*
 * Parses XMP packet and fills metadata with data from XMP
 *
 * @param xmp_data pointer to XMP packet
 * @param xmp_size size of XMP packet
 * @param metadata place to store HDR metadata values
 * @return true if metadata is successfully retrieved, false otherwise
*/
bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata);

}

#endif //ANDROID_JPEGRECOVERYMAP_RECOVERYMAPUTILS_H
 No newline at end of file
+73 −0
Original line number Diff line number Diff line
@@ -20,8 +20,15 @@

#include <errno.h>
#include <setjmp.h>
#include <string>

using namespace std;

namespace android::recoverymap {

const uint32_t kExifMarker = JPEG_APP0 + 1;
const uint32_t kICCMarker = JPEG_APP0 + 2;

struct jpegr_source_mgr : jpeg_source_mgr {
    jpegr_source_mgr(const uint8_t* ptr, int len);
    ~jpegr_source_mgr();
@@ -88,6 +95,7 @@ bool JpegDecoder::decompressImage(const void* image, int length) {
    }

    mResultBuffer.clear();
    mXMPBuffer.clear();
    if (!decode(image, length)) {
        return false;
    }
@@ -103,6 +111,15 @@ size_t JpegDecoder::getDecompressedImageSize() {
    return mResultBuffer.size();
}

void* JpegDecoder::getXMPPtr() {
    return mXMPBuffer.data();
}

size_t JpegDecoder::getXMPSize() {
    return mXMPBuffer.size();
}


size_t JpegDecoder::getDecompressedImageWidth() {
    return mWidth;
}
@@ -115,6 +132,8 @@ bool JpegDecoder::decode(const void* image, int length) {
    jpeg_decompress_struct cinfo;
    jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
    jpegrerror_mgr myerr;
    string nameSpace = "http://ns.adobe.com/xap/1.0/";

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

@@ -124,9 +143,26 @@ bool JpegDecoder::decode(const void* image, int length) {
    }
    jpeg_create_decompress(&cinfo);

    jpeg_save_markers(&cinfo, kExifMarker, 0xFFFF);

    cinfo.src = &mgr;
    jpeg_read_header(&cinfo, TRUE);

    // Save XMP Data
    for (jpeg_marker_struct* marker = cinfo.marker_list; marker; marker = marker->next) {
        if (marker->marker == kExifMarker) {
            const unsigned int len = marker->data_length;
            if (len > nameSpace.size() &&
                !strncmp(reinterpret_cast<const char*>(marker->data),
                         nameSpace.c_str(), nameSpace.size())) {
                mXMPBuffer.resize(len+1, 0);
                memcpy(static_cast<void*>(mXMPBuffer.data()), marker->data, len);
                break;
            }
        }
    }


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

@@ -161,6 +197,43 @@ bool JpegDecoder::decompress(jpeg_decompress_struct* cinfo, const uint8_t* dest,
    return decompressYUV(cinfo, dest);
}

bool JpegDecoder::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;
    }
    jpeg_create_decompress(&cinfo);

    jpeg_save_markers(&cinfo, kExifMarker, 0xFFFF);
    jpeg_save_markers(&cinfo, kICCMarker, 0xFFFF);

    cinfo.src = &mgr;
    if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
        jpeg_destroy_decompress(&cinfo);
        return false;
    }

    *pWidth = cinfo.image_width;
    *pHeight = cinfo.image_height;

    //TODO: Parse iccProfile and exifData
    (void)iccData;
    (void)exifData;


    jpeg_destroy_decompress(&cinfo);
    return true;
}


bool JpegDecoder::decompressYUV(jpeg_decompress_struct* cinfo, const uint8_t* dest) {

    JSAMPROW y[kCompressBatchSize];
Loading