diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-12 23:19:28 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-12 23:19:28 +0000 |
commit | 1f55e13b8219eeeb52ba0f4b5ad4fc355975332c (patch) | |
tree | 32cec1f2a9fbbe77966f55606a7816253697210e | |
parent | 66f7ed10941a1e9819c5d35da60aef495ef44985 (diff) | |
parent | 094946bd8c1a8f205417a21755023118857950f7 (diff) | |
download | native-1f55e13b8219eeeb52ba0f4b5ad4fc355975332c.tar.gz |
Snap for 10306978 from 094946bd8c1a8f205417a21755023118857950f7 to udc-release
Change-Id: I33a57c02c86b15f2eb53b263d762697c24d3f170
-rw-r--r-- | libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp | 7 | ||||
-rw-r--r-- | libs/ultrahdr/include/ultrahdr/gainmapmath.h | 8 | ||||
-rw-r--r-- | libs/ultrahdr/include/ultrahdr/jpegr.h | 9 | ||||
-rw-r--r-- | libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h | 2 | ||||
-rw-r--r-- | libs/ultrahdr/include/ultrahdr/ultrahdr.h | 16 | ||||
-rw-r--r-- | libs/ultrahdr/jpegr.cpp | 56 | ||||
-rw-r--r-- | libs/ultrahdr/jpegrutils.cpp | 254 | ||||
-rw-r--r-- | libs/ultrahdr/tests/data/minnie-320x240-yuv-icc.jpg | bin | 37101 -> 34266 bytes | |||
-rw-r--r-- | libs/ultrahdr/tests/jpegr_test.cpp | 64 |
9 files changed, 394 insertions, 22 deletions
diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp index acb9b795c0..bbe58e0f2e 100644 --- a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp +++ b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp @@ -249,7 +249,7 @@ void UltraHdrEncFuzzer::process() { jpegGainMap.data = gainMapEncoder.getCompressedImagePtr(); jpegGainMap.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; ultrahdr_metadata_struct metadata; - metadata.version = "1.3.1"; + metadata.version = "1.0"; if (tf == ULTRAHDR_TF_HLG) { metadata.maxContentBoost = kHlgMaxNits / kSdrWhiteNits; } else if (tf == ULTRAHDR_TF_PQ) { @@ -258,6 +258,11 @@ void UltraHdrEncFuzzer::process() { metadata.maxContentBoost = 1.0f; } metadata.minContentBoost = 1.0f; + metadata.gamma = 1.0f; + metadata.offsetSdr = 0.0f; + metadata.offsetHdr = 0.0f; + metadata.hdrCapacityMin = 1.0f; + metadata.hdrCapacityMax = metadata.maxContentBoost; status = jpegHdr.encodeJPEGR(&jpegImg, &jpegGainMap, &metadata, &jpegImgR); } } diff --git a/libs/ultrahdr/include/ultrahdr/gainmapmath.h b/libs/ultrahdr/include/ultrahdr/gainmapmath.h index 13832db752..edf152d8ed 100644 --- a/libs/ultrahdr/include/ultrahdr/gainmapmath.h +++ b/libs/ultrahdr/include/ultrahdr/gainmapmath.h @@ -414,6 +414,10 @@ void transformYuv420(jr_uncompressed_ptr image, size_t x_chroma, size_t y_chroma /* * Calculate the 8-bit unsigned integer gain value for the given SDR and HDR * luminances in linear space, and the hdr ratio to encode against. + * + * Note: since this library always uses gamma of 1.0, offsetSdr of 0.0, and + * offsetHdr of 0.0, this function doesn't handle different metadata values for + * these fields. */ uint8_t encodeGain(float y_sdr, float y_hdr, ultrahdr_metadata_ptr metadata); uint8_t encodeGain(float y_sdr, float y_hdr, ultrahdr_metadata_ptr metadata, @@ -422,6 +426,10 @@ uint8_t encodeGain(float y_sdr, float y_hdr, ultrahdr_metadata_ptr metadata, /* * Calculates the linear luminance in nits after applying the given gain * value, with the given hdr ratio, to the given sdr input in the range [0, 1]. + * + * Note: similar to encodeGain(), this function only supports gamma 1.0, + * offsetSdr 0.0, offsetHdr 0.0, hdrCapacityMin 1.0, and hdrCapacityMax equal to + * gainMapMax, as this library encodes. */ Color applyGain(Color e, float gain, ultrahdr_metadata_ptr metadata); Color applyGain(Color e, float gain, ultrahdr_metadata_ptr metadata, float displayBoost); diff --git a/libs/ultrahdr/include/ultrahdr/jpegr.h b/libs/ultrahdr/include/ultrahdr/jpegr.h index 9546ca4762..a35fd30634 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegr.h +++ b/libs/ultrahdr/include/ultrahdr/jpegr.h @@ -222,7 +222,11 @@ public: * Decompress JPEGR image. * * This method assumes that the JPEGR image contains an ICC profile with primaries that match - * those of a color gamut that this library is aware of; Bt.709, Display-P3, or Bt.2100. + * those of a color gamut that this library is aware of; Bt.709, Display-P3, or Bt.2100. It also + * assumes the base image uses the sRGB transfer function. + * + * This method only supports single gain map metadata values for fields that allow multi-channel + * metadata values. * * @param compressed_jpegr_image compressed JPEGR image. * @param dest destination of the uncompressed JPEGR image. @@ -265,6 +269,9 @@ public: /* * Gets Info from JPEGR file without decoding it. * + * This method only supports single gain map metadata values for fields that allow multi-channel + * metadata values. + * * The output is filled jpegr_info structure * @param compressed_jpegr_image compressed JPEGR image * @param jpegr_info pointer to output JPEGR info. Members of jpegr_info diff --git a/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h b/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h index 9f59c3eaf3..064123210f 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h +++ b/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h @@ -42,6 +42,8 @@ enum { ERROR_JPEGR_BUFFER_TOO_SMALL = JPEGR_IO_ERROR_BASE - 4, ERROR_JPEGR_INVALID_COLORGAMUT = JPEGR_IO_ERROR_BASE - 5, ERROR_JPEGR_INVALID_TRANS_FUNC = JPEGR_IO_ERROR_BASE - 6, + ERROR_JPEGR_INVALID_METADATA = JPEGR_IO_ERROR_BASE - 7, + ERROR_JPEGR_UNSUPPORTED_METADATA = JPEGR_IO_ERROR_BASE - 8, JPEGR_RUNTIME_ERROR_BASE = -20000, ERROR_JPEGR_ENCODE_ERROR = JPEGR_RUNTIME_ERROR_BASE - 1, diff --git a/libs/ultrahdr/include/ultrahdr/ultrahdr.h b/libs/ultrahdr/include/ultrahdr/ultrahdr.h index 21751b4634..17cc97173c 100644 --- a/libs/ultrahdr/include/ultrahdr/ultrahdr.h +++ b/libs/ultrahdr/include/ultrahdr/ultrahdr.h @@ -49,14 +49,28 @@ typedef enum { /* * Holds information for gain map related metadata. + * + * Not: all values stored in linear. This differs from the metadata encoding in XMP, where + * maxContentBoost (aka gainMapMax), minContentBoost (aka gainMapMin), hdrCapacityMin, and + * hdrCapacityMax are stored in log2 space. */ struct ultrahdr_metadata_struct { - // Ultra HDR library version + // Ultra HDR format version std::string version; // Max Content Boost for the map float maxContentBoost; // Min Content Boost for the map float minContentBoost; + // Gamma of the map data + float gamma; + // Offset for SDR data in map calculations + float offsetSdr; + // Offset for HDR data in map calculations + float offsetHdr; + // HDR capacity to apply the map at all + float hdrCapacityMin; + // HDR capacity to apply the map completely + float hdrCapacityMax; }; typedef struct ultrahdr_metadata_struct* ultrahdr_metadata_ptr; diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp index 9af5af75e5..9c57f34c2a 100644 --- a/libs/ultrahdr/jpegr.cpp +++ b/libs/ultrahdr/jpegr.cpp @@ -644,13 +644,18 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, ultrahdr_metadata_struct uhdr_metadata; if (!getMetadataFromXMP(static_cast<uint8_t*>(gain_map_decoder.getXMPPtr()), gain_map_decoder.getXMPSize(), &uhdr_metadata)) { - return ERROR_JPEGR_DECODE_ERROR; + return ERROR_JPEGR_INVALID_METADATA; } if (metadata != nullptr) { metadata->version = uhdr_metadata.version; metadata->minContentBoost = uhdr_metadata.minContentBoost; metadata->maxContentBoost = uhdr_metadata.maxContentBoost; + metadata->gamma = uhdr_metadata.gamma; + metadata->offsetSdr = uhdr_metadata.offsetSdr; + metadata->offsetHdr = uhdr_metadata.offsetHdr; + metadata->hdrCapacityMin = uhdr_metadata.hdrCapacityMin; + metadata->hdrCapacityMax = uhdr_metadata.hdrCapacityMax; } if (output_format == ULTRAHDR_OUTPUT_SDR) { @@ -840,6 +845,12 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, metadata->maxContentBoost = hdr_white_nits / kSdrWhiteNits; metadata->minContentBoost = 1.0f; + metadata->gamma = 1.0f; + metadata->offsetSdr = 0.0f; + metadata->offsetHdr = 0.0f; + metadata->hdrCapacityMin = 1.0f; + metadata->hdrCapacityMax = metadata->maxContentBoost; + float log2MinBoost = log2(metadata->minContentBoost); float log2MaxBoost = log2(metadata->maxContentBoost); @@ -958,6 +969,26 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, return ERROR_JPEGR_INVALID_NULL_PTR; } + if (metadata->version.compare("1.0")) { + ALOGE("Unsupported metadata version: %s", metadata->version.c_str()); + return ERROR_JPEGR_UNSUPPORTED_METADATA; + } + if (metadata->gamma != 1.0f) { + ALOGE("Unsupported metadata gamma: %f", metadata->gamma); + return ERROR_JPEGR_UNSUPPORTED_METADATA; + } + if (metadata->offsetSdr != 0.0f || metadata->offsetHdr != 0.0f) { + ALOGE("Unsupported metadata offset sdr, hdr: %f, %f", metadata->offsetSdr, + metadata->offsetHdr); + return ERROR_JPEGR_UNSUPPORTED_METADATA; + } + if (metadata->hdrCapacityMin != metadata->minContentBoost + || metadata->hdrCapacityMax != metadata->maxContentBoost) { + ALOGE("Unsupported metadata hdr capacity min, max: %f, %f", metadata->hdrCapacityMin, + metadata->hdrCapacityMax); + return ERROR_JPEGR_UNSUPPORTED_METADATA; + } + // TODO: remove once map scaling factor is computed based on actual map dims size_t image_width = uncompressed_yuv_420_image->width; size_t image_height = uncompressed_yuv_420_image->height; @@ -1180,12 +1211,33 @@ status_t JpegR::appendGainMap(jr_compressed_ptr compressed_jpeg_image, return ERROR_JPEGR_INVALID_NULL_PTR; } - if (metadata->minContentBoost < 1.0f || metadata->maxContentBoost < metadata->minContentBoost) { + if (metadata->version.compare("1.0")) { + ALOGE("received bad value for version: %s", metadata->version.c_str()); + return ERROR_JPEGR_INVALID_INPUT_TYPE; + } + if (metadata->maxContentBoost < metadata->minContentBoost) { ALOGE("received bad value for content boost min %f, max %f", metadata->minContentBoost, metadata->maxContentBoost); return ERROR_JPEGR_INVALID_INPUT_TYPE; } + if (metadata->hdrCapacityMax < metadata->hdrCapacityMin || metadata->hdrCapacityMin < 1.0f) { + ALOGE("received bad value for hdr capacity min %f, max %f", metadata->hdrCapacityMin, + metadata->hdrCapacityMax); + return ERROR_JPEGR_INVALID_INPUT_TYPE; + } + + if (metadata->offsetSdr < 0.0f || metadata->offsetHdr < 0.0f) { + ALOGE("received bad value for offset sdr %f, hdr %f", metadata->offsetSdr, + metadata->offsetHdr); + return ERROR_JPEGR_INVALID_INPUT_TYPE; + } + + if (metadata->gamma <= 0.0f) { + ALOGE("received bad value for gamma %f", metadata->gamma); + return ERROR_JPEGR_INVALID_INPUT_TYPE; + } + const string nameSpace = "http://ns.adobe.com/xap/1.0/"; const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator diff --git a/libs/ultrahdr/jpegrutils.cpp b/libs/ultrahdr/jpegrutils.cpp index 6430af12c7..c434eb6459 100644 --- a/libs/ultrahdr/jpegrutils.cpp +++ b/libs/ultrahdr/jpegrutils.cpp @@ -113,6 +113,15 @@ public: XMPXmlHandler() : XmlHandler() { state = NotStrarted; + versionFound = false; + minContentBoostFound = false; + maxContentBoostFound = false; + gammaFound = false; + offsetSdrFound = false; + offsetHdrFound = false; + hdrCapacityMinFound = false; + hdrCapacityMaxFound = false; + baseRenditionIsHdrFound = false; } enum ParseState { @@ -147,10 +156,24 @@ public: string val; if (state == Started) { if (context.BuildTokenValue(&val)) { - if (!val.compare(maxContentBoostAttrName)) { + if (!val.compare(versionAttrName)) { + lastAttributeName = versionAttrName; + } else if (!val.compare(maxContentBoostAttrName)) { lastAttributeName = maxContentBoostAttrName; } else if (!val.compare(minContentBoostAttrName)) { lastAttributeName = minContentBoostAttrName; + } else if (!val.compare(gammaAttrName)) { + lastAttributeName = gammaAttrName; + } else if (!val.compare(offsetSdrAttrName)) { + lastAttributeName = offsetSdrAttrName; + } else if (!val.compare(offsetHdrAttrName)) { + lastAttributeName = offsetHdrAttrName; + } else if (!val.compare(hdrCapacityMinAttrName)) { + lastAttributeName = hdrCapacityMinAttrName; + } else if (!val.compare(hdrCapacityMaxAttrName)) { + lastAttributeName = hdrCapacityMaxAttrName; + } else if (!val.compare(baseRenditionIsHdrAttrName)) { + lastAttributeName = baseRenditionIsHdrAttrName; } else { lastAttributeName = ""; } @@ -163,18 +186,52 @@ public: string val; if (state == Started) { if (context.BuildTokenValue(&val, true)) { - if (!lastAttributeName.compare(maxContentBoostAttrName)) { + if (!lastAttributeName.compare(versionAttrName)) { + versionStr = val; + versionFound = true; + } else if (!lastAttributeName.compare(maxContentBoostAttrName)) { maxContentBoostStr = val; + maxContentBoostFound = true; } else if (!lastAttributeName.compare(minContentBoostAttrName)) { minContentBoostStr = val; + minContentBoostFound = true; + } else if (!lastAttributeName.compare(gammaAttrName)) { + gammaStr = val; + gammaFound = true; + } else if (!lastAttributeName.compare(offsetSdrAttrName)) { + offsetSdrStr = val; + offsetSdrFound = true; + } else if (!lastAttributeName.compare(offsetHdrAttrName)) { + offsetHdrStr = val; + offsetHdrFound = true; + } else if (!lastAttributeName.compare(hdrCapacityMinAttrName)) { + hdrCapacityMinStr = val; + hdrCapacityMinFound = true; + } else if (!lastAttributeName.compare(hdrCapacityMaxAttrName)) { + hdrCapacityMaxStr = val; + hdrCapacityMaxFound = true; + } else if (!lastAttributeName.compare(baseRenditionIsHdrAttrName)) { + baseRenditionIsHdrStr = val; + baseRenditionIsHdrFound = true; } } } return context.GetResult(); } - bool getMaxContentBoost(float* max_content_boost) { + bool getVersion(string* version, bool* present) { if (state == Done) { + *version = versionStr; + *present = versionFound; + return true; + } else { + return false; + } + } + + bool getMaxContentBoost(float* max_content_boost, bool* present) { + if (state == Done) { + *present = maxContentBoostFound; stringstream ss(maxContentBoostStr); float val; if (ss >> val) { @@ -188,8 +245,9 @@ public: } } - bool getMinContentBoost(float* min_content_boost) { + bool getMinContentBoost(float* min_content_boost, bool* present) { if (state == Done) { + *present = minContentBoostFound; stringstream ss(minContentBoostStr); float val; if (ss >> val) { @@ -203,12 +261,141 @@ public: } } + bool getGamma(float* gamma, bool* present) { + if (state == Done) { + *present = gammaFound; + stringstream ss(gammaStr); + float val; + if (ss >> val) { + *gamma = val; + return true; + } else { + return false; + } + } else { + return false; + } + } + + + bool getOffsetSdr(float* offset_sdr, bool* present) { + if (state == Done) { + *present = offsetSdrFound; + stringstream ss(offsetSdrStr); + float val; + if (ss >> val) { + *offset_sdr = val; + return true; + } else { + return false; + } + } else { + return false; + } + } + + + bool getOffsetHdr(float* offset_hdr, bool* present) { + if (state == Done) { + *present = offsetHdrFound; + stringstream ss(offsetHdrStr); + float val; + if (ss >> val) { + *offset_hdr = val; + return true; + } else { + return false; + } + } else { + return false; + } + } + + + bool getHdrCapacityMin(float* hdr_capacity_min, bool* present) { + if (state == Done) { + *present = hdrCapacityMinFound; + stringstream ss(hdrCapacityMinStr); + float val; + if (ss >> val) { + *hdr_capacity_min = exp2(val); + return true; + } else { + return false; + } + } else { + return false; + } + } + + + bool getHdrCapacityMax(float* hdr_capacity_max, bool* present) { + if (state == Done) { + *present = hdrCapacityMaxFound; + stringstream ss(hdrCapacityMaxStr); + float val; + if (ss >> val) { + *hdr_capacity_max = exp2(val); + return true; + } else { + return false; + } + } else { + return false; + } + } + + + bool getBaseRenditionIsHdr(bool* base_rendition_is_hdr, bool* present) { + if (state == Done) { + *present = baseRenditionIsHdrFound; + if (!baseRenditionIsHdrStr.compare("False")) { + *base_rendition_is_hdr = false; + return true; + } else if (!baseRenditionIsHdrStr.compare("True")) { + *base_rendition_is_hdr = true; + return true; + } else { + return false; + } + } else { + return false; + } + } + + + private: static const string containerName; + + static const string versionAttrName; + string versionStr; + bool versionFound; static const string maxContentBoostAttrName; string maxContentBoostStr; + bool maxContentBoostFound; static const string minContentBoostAttrName; string minContentBoostStr; + bool minContentBoostFound; + static const string gammaAttrName; + string gammaStr; + bool gammaFound; + static const string offsetSdrAttrName; + string offsetSdrStr; + bool offsetSdrFound; + static const string offsetHdrAttrName; + string offsetHdrStr; + bool offsetHdrFound; + static const string hdrCapacityMinAttrName; + string hdrCapacityMinStr; + bool hdrCapacityMinFound; + static const string hdrCapacityMaxAttrName; + string hdrCapacityMaxStr; + bool hdrCapacityMaxFound; + static const string baseRenditionIsHdrAttrName; + string baseRenditionIsHdrStr; + bool baseRenditionIsHdrFound; + string lastAttributeName; ParseState state; }; @@ -253,8 +440,15 @@ const string kMapHDRCapacityMax = Name(kGainMapPrefix, "HDRCapacityMax"); const string kMapBaseRenditionIsHDR = Name(kGainMapPrefix, "BaseRenditionIsHDR"); // GainMap XMP constants - names for XMP handlers +const string XMPXmlHandler::versionAttrName = kMapVersion; const string XMPXmlHandler::minContentBoostAttrName = kMapGainMapMin; const string XMPXmlHandler::maxContentBoostAttrName = kMapGainMapMax; +const string XMPXmlHandler::gammaAttrName = kMapGamma; +const string XMPXmlHandler::offsetSdrAttrName = kMapOffsetSdr; +const string XMPXmlHandler::offsetHdrAttrName = kMapOffsetHdr; +const string XMPXmlHandler::hdrCapacityMinAttrName = kMapHDRCapacityMin; +const string XMPXmlHandler::hdrCapacityMaxAttrName = kMapHDRCapacityMax; +const string XMPXmlHandler::baseRenditionIsHdrAttrName = kMapBaseRenditionIsHDR; bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, ultrahdr_metadata_struct* metadata) { string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; @@ -291,11 +485,48 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, ultrahdr_metadata_st return false; } - if (!handler.getMaxContentBoost(&metadata->maxContentBoost)) { + // Apply default values to any not-present fields, except for Version, + // maxContentBoost, and hdrCapacityMax, which are required. Return false if + // we encounter a present field that couldn't be parsed, since this + // indicates it is invalid (eg. string where there should be a float). + bool present = false; + if (!handler.getVersion(&metadata->version, &present) || !present) { + return false; + } + if (!handler.getMaxContentBoost(&metadata->maxContentBoost, &present) || !present) { + return false; + } + if (!handler.getHdrCapacityMax(&metadata->hdrCapacityMax, &present) || !present) { return false; } + if (!handler.getMinContentBoost(&metadata->minContentBoost, &present)) { + if (present) return false; + metadata->minContentBoost = 1.0f; + } + if (!handler.getGamma(&metadata->gamma, &present)) { + if (present) return false; + metadata->gamma = 1.0f; + } + if (!handler.getOffsetSdr(&metadata->offsetSdr, &present)) { + if (present) return false; + metadata->offsetSdr = 1.0f / 64.0f; + } + if (!handler.getOffsetHdr(&metadata->offsetHdr, &present)) { + if (present) return false; + metadata->offsetHdr = 1.0f / 64.0f; + } + if (!handler.getHdrCapacityMin(&metadata->hdrCapacityMin, &present)) { + if (present) return false; + metadata->hdrCapacityMin = 1.0f; + } - if (!handler.getMinContentBoost(&metadata->minContentBoost)) { + bool base_rendition_is_hdr; + if (!handler.getBaseRenditionIsHdr(&base_rendition_is_hdr, &present)) { + if (present) return false; + base_rendition_is_hdr = false; + } + if (base_rendition_is_hdr) { + ALOGE("Base rendition of HDR is not supported!"); return false; } @@ -355,12 +586,11 @@ string generateXmpForSecondaryImage(ultrahdr_metadata_struct& metadata) { writer.WriteAttributeNameAndValue(kMapVersion, metadata.version); writer.WriteAttributeNameAndValue(kMapGainMapMin, log2(metadata.minContentBoost)); writer.WriteAttributeNameAndValue(kMapGainMapMax, log2(metadata.maxContentBoost)); - writer.WriteAttributeNameAndValue(kMapGamma, "1"); - writer.WriteAttributeNameAndValue(kMapOffsetSdr, "0"); - writer.WriteAttributeNameAndValue(kMapOffsetHdr, "0"); - writer.WriteAttributeNameAndValue( - kMapHDRCapacityMin, std::max(log2(metadata.minContentBoost), 0.0f)); - writer.WriteAttributeNameAndValue(kMapHDRCapacityMax, log2(metadata.maxContentBoost)); + writer.WriteAttributeNameAndValue(kMapGamma, metadata.gamma); + writer.WriteAttributeNameAndValue(kMapOffsetSdr, metadata.offsetSdr); + writer.WriteAttributeNameAndValue(kMapOffsetHdr, metadata.offsetHdr); + writer.WriteAttributeNameAndValue(kMapHDRCapacityMin, log2(metadata.hdrCapacityMin)); + writer.WriteAttributeNameAndValue(kMapHDRCapacityMax, log2(metadata.hdrCapacityMax)); writer.WriteAttributeNameAndValue(kMapBaseRenditionIsHDR, "False"); writer.FinishWriting(); diff --git a/libs/ultrahdr/tests/data/minnie-320x240-yuv-icc.jpg b/libs/ultrahdr/tests/data/minnie-320x240-yuv-icc.jpg Binary files differindex f61e0e8525..c7f4538534 100644 --- a/libs/ultrahdr/tests/data/minnie-320x240-yuv-icc.jpg +++ b/libs/ultrahdr/tests/data/minnie-320x240-yuv-icc.jpg diff --git a/libs/ultrahdr/tests/jpegr_test.cpp b/libs/ultrahdr/tests/jpegr_test.cpp index d482ea1f79..41d55ec497 100644 --- a/libs/ultrahdr/tests/jpegr_test.cpp +++ b/libs/ultrahdr/tests/jpegr_test.cpp @@ -819,6 +819,52 @@ TEST_F(JpegRTest, encodeAPI4ForInvalidArgs) { EXPECT_NE(OK, jpegRCodec.encodeJPEGR( &jpegR, nullptr, nullptr, &jpegR)) << "fail, API allows nullptr gainmap image"; + // test metadata + ultrahdr_metadata_struct good_metadata; + good_metadata.version = "1.0"; + good_metadata.minContentBoost = 1.0f; + good_metadata.maxContentBoost = 2.0f; + good_metadata.gamma = 1.0f; + good_metadata.offsetSdr = 0.0f; + good_metadata.offsetHdr = 0.0f; + good_metadata.hdrCapacityMin = 1.0f; + good_metadata.hdrCapacityMax = 2.0f; + + ultrahdr_metadata_struct metadata = good_metadata; + metadata.version = "1.1"; + EXPECT_NE(OK, jpegRCodec.encodeJPEGR( + &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata version"; + + metadata = good_metadata; + metadata.minContentBoost = 3.0f; + EXPECT_NE(OK, jpegRCodec.encodeJPEGR( + &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata content boost"; + + metadata = good_metadata; + metadata.gamma = -0.1f; + EXPECT_NE(OK, jpegRCodec.encodeJPEGR( + &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata gamma"; + + metadata = good_metadata; + metadata.offsetSdr = -0.1f; + EXPECT_NE(OK, jpegRCodec.encodeJPEGR( + &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata offset sdr"; + + metadata = good_metadata; + metadata.offsetHdr = -0.1f; + EXPECT_NE(OK, jpegRCodec.encodeJPEGR( + &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata offset hdr"; + + metadata = good_metadata; + metadata.hdrCapacityMax = 0.5f; + EXPECT_NE(OK, jpegRCodec.encodeJPEGR( + &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata hdr capacity max"; + + metadata = good_metadata; + metadata.hdrCapacityMin = 0.5f; + EXPECT_NE(OK, jpegRCodec.encodeJPEGR( + &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata hdr capacity min"; + free(jpegR.data); } @@ -864,8 +910,13 @@ TEST_F(JpegRTest, decodeAPIForInvalidArgs) { TEST_F(JpegRTest, writeXmpThenRead) { ultrahdr_metadata_struct metadata_expected; metadata_expected.version = "1.0"; - metadata_expected.maxContentBoost = 1.25; - metadata_expected.minContentBoost = 0.75; + metadata_expected.maxContentBoost = 1.25f; + metadata_expected.minContentBoost = 0.75f; + metadata_expected.gamma = 1.0f; + metadata_expected.offsetSdr = 0.0f; + metadata_expected.offsetHdr = 0.0f; + metadata_expected.hdrCapacityMin = 1.0f; + metadata_expected.hdrCapacityMax = metadata_expected.maxContentBoost; const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator @@ -882,6 +933,11 @@ TEST_F(JpegRTest, writeXmpThenRead) { EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read)); EXPECT_FLOAT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost); EXPECT_FLOAT_EQ(metadata_expected.minContentBoost, metadata_read.minContentBoost); + EXPECT_FLOAT_EQ(metadata_expected.gamma, metadata_read.gamma); + EXPECT_FLOAT_EQ(metadata_expected.offsetSdr, metadata_read.offsetSdr); + EXPECT_FLOAT_EQ(metadata_expected.offsetHdr, metadata_read.offsetHdr); + EXPECT_FLOAT_EQ(metadata_expected.hdrCapacityMin, metadata_read.hdrCapacityMin); + EXPECT_FLOAT_EQ(metadata_expected.hdrCapacityMax, metadata_read.hdrCapacityMax); } /* Test Encode API-0 */ @@ -1297,9 +1353,7 @@ TEST_F(JpegRTest, ProfileGainMapFuncs) { JpegRBenchmark benchmark; - ultrahdr_metadata_struct metadata = { .version = "1.0", - .maxContentBoost = 8.0f, - .minContentBoost = 1.0f / 8.0f }; + ultrahdr_metadata_struct metadata = { .version = "1.0" }; jpegr_uncompressed_struct map = { .data = NULL, .width = 0, |