Loading libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h +8 −42 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ namespace android::recoverymap { // Color gamuts for image data typedef enum { JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT709, Loading @@ -28,7 +29,7 @@ typedef enum { JPEGR_COLORGAMUT_BT2100, } jpegr_color_gamut; // Transfer functions as defined for XMP metadata // Transfer functions for image data typedef enum { JPEGR_TF_UNSPECIFIED = -1, JPEGR_TF_LINEAR = 0, Loading Loading @@ -82,45 +83,11 @@ struct jpegr_exif_struct { int length; }; struct chromaticity_coord { float x; float y; }; struct st2086_metadata { // xy chromaticity coordinate of the red primary of the mastering display chromaticity_coord redPrimary; // xy chromaticity coordinate of the green primary of the mastering display chromaticity_coord greenPrimary; // xy chromaticity coordinate of the blue primary of the mastering display chromaticity_coord bluePrimary; // xy chromaticity coordinate of the white point of the mastering display chromaticity_coord whitePoint; // Maximum luminance in nits of the mastering display uint32_t maxLuminance; // Minimum luminance in nits of the mastering display float minLuminance; }; struct hdr10_metadata { // Mastering display color volume st2086_metadata st2086Metadata; // Max frame average light level in nits float maxFALL; // Max content light level in nits float maxCLL; }; struct jpegr_metadata { // JPEG/R version uint32_t version; // Range scaling factor for the map float rangeScalingFactor; // The transfer function for decoding the HDR representation of the image jpegr_transfer_function transferFunction; // HDR10 metadata, only applicable for transferFunction of JPEGR_TF_PQ hdr10_metadata hdr10Metadata; // Max Content Boost for the map float maxContentBoost; }; typedef struct jpegr_uncompressed_struct* jr_uncompressed_ptr; Loading Loading @@ -270,14 +237,14 @@ private: * * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format * @param uncompressed_p010_image uncompressed HDR image in P010 color format * @param hdr_tf transfer function of the HDR image * @param dest recovery map; caller responsible for memory of data * @param metadata metadata provides the transfer function for the HDR * image; range_scaling_factor and hdr10 FALL and CLL will * be updated. * @param metadata max_content_boost is filled in * @return NO_ERROR if calculation succeeds, error code if error occurs. */ status_t generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, jr_uncompressed_ptr uncompressed_p010_image, jpegr_transfer_function hdr_tf, jr_metadata_ptr metadata, jr_uncompressed_ptr dest); Loading @@ -285,8 +252,7 @@ private: * This method is called in the decoding pipeline. It will take the uncompressed (decoded) * 8-bit yuv image, the uncompressed (decoded) recovery map, and extracted JPEG/R metadata as * input, and calculate the 10-bit recovered image. The recovered output image is the same * color gamut as the SDR image, with the transfer function specified in the JPEG/R metadata, * and is in RGBA1010102 data format. * color gamut as the SDR image, with HLG transfer function, and is in RGBA1010102 data format. * * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format * @param uncompressed_recovery_map uncompressed recovery map Loading libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h +14 −19 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta * * below is an example of the XMP metadata that this function generates where * secondary_image_length = 1000 * range_scaling_factor = 1.25 * max_content_boost = 8.0 * * <x:xmpmeta * xmlns:x="adobe:ns:meta/" Loading @@ -63,31 +63,26 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta * <rdf:RDF * xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> * <rdf:Description * xmlns:GContainer="http://ns.google.com/photos/1.0/container/" * xmlns:Container="http://ns.google.com/photos/1.0/container/" * xmlns:Item="http://ns.google.com/photos/1.0/container/item/" * xmlns:RecoveryMap="http://ns.google.com/photos/1.0/recoverymap/"> * <GContainer:Version>1</GContainer:Version> * <GContainer:Directory> * <Container:Directory> * <rdf:Seq> * <rdf:li> * <GContainer:Item * GContainer:ItemSemantic="Primary" * GContainer:ItemMime="image/jpeg" * RecoveryMap:Version=”1” * RecoveryMap:RangeScalingFactor=”1.25” * RecoveryMap:TransferFunction=”2”/> * <RecoveryMap:HDR10Metadata * // some attributes * // some elements * </RecoveryMap:HDR10Metadata> * <Container:Item * Item:Semantic="Primary" * Item:Mime="image/jpeg" * RecoveryMap:Version="1" * RecoveryMap:MaxContentBoost="8.0"/> * </rdf:li> * <rdf:li> * <GContainer:Item * GContainer:ItemSemantic="RecoveryMap" * GContainer:ItemMime="image/jpeg" * GContainer:ItemLength="1000"/> * <Container:Item * Item:Semantic="RecoveryMap" * Item:Mime="image/jpeg" * Item:Length="1000"/> * </rdf:li> * </rdf:Seq> * </GContainer:Directory> * </Container:Directory> * </rdf:Description> * </rdf:RDF> * </x:xmpmeta> Loading libs/jpegrecoverymap/recoverymap.cpp +15 −63 Original line number Diff line number Diff line Loading @@ -72,16 +72,6 @@ static const size_t kJpegBlock = 8; // JPEG compress quality (0 ~ 100) for recovery map static const int kMapCompressQuality = 85; // TODO: fill in st2086 metadata static const st2086_metadata kSt2086Metadata = { {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, 0, 1.0f, }; #define CONFIG_MULTITHREAD 1 int GetCPUCoreCount() { int cpuCoreCount = 1; Loading Loading @@ -133,10 +123,6 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_metadata metadata; metadata.version = kJpegrVersion; metadata.transferFunction = hdr_tf; if (hdr_tf == JPEGR_TF_PQ) { metadata.hdr10Metadata.st2086Metadata = kSt2086Metadata; } jpegr_uncompressed_struct uncompressed_yuv_420_image; unique_ptr<uint8_t[]> uncompressed_yuv_420_image_data = make_unique<uint8_t[]>( Loading @@ -146,7 +132,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( &uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); &uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); Loading Loading @@ -207,14 +193,10 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_metadata metadata; metadata.version = kJpegrVersion; metadata.transferFunction = hdr_tf; if (hdr_tf == JPEGR_TF_PQ) { metadata.hdr10Metadata.st2086Metadata = kSt2086Metadata; } jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); Loading Loading @@ -271,14 +253,10 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_metadata metadata; metadata.version = kJpegrVersion; metadata.transferFunction = hdr_tf; if (hdr_tf == JPEGR_TF_PQ) { metadata.hdr10Metadata.st2086Metadata = kSt2086Metadata; } jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); Loading Loading @@ -328,14 +306,10 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_metadata metadata; metadata.version = kJpegrVersion; metadata.transferFunction = hdr_tf; if (hdr_tf == JPEGR_TF_PQ) { metadata.hdr10Metadata.st2086Metadata = kSt2086Metadata; } jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( &uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); &uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); Loading Loading @@ -437,7 +411,6 @@ status_t RecoveryMap::compressRecoveryMap(jr_uncompressed_ptr uncompressed_recov return ERROR_JPEGR_INVALID_NULL_PTR; } // TODO: should we have ICC data for the map? JpegEncoder jpeg_encoder; if (!jpeg_encoder.compressImage(uncompressed_recovery_map->data, uncompressed_recovery_map->width, Loading Loading @@ -518,6 +491,7 @@ void JobQueue::reset() { status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, jr_uncompressed_ptr uncompressed_p010_image, jpegr_transfer_function hdr_tf, jr_metadata_ptr metadata, jr_uncompressed_ptr dest) { if (uncompressed_yuv_420_image == nullptr Loading Loading @@ -554,7 +528,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 ColorTransformFn hdrInvOetf = nullptr; float hdr_white_nits = 0.0f; switch (metadata->transferFunction) { switch (hdr_tf) { case JPEGR_TF_LINEAR: hdrInvOetf = identityConversion; break; Loading Loading @@ -658,7 +632,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 size_t pixel_idx = x + y * dest->width; reinterpret_cast<uint8_t*>(dest->data)[pixel_idx] = encodeRecovery(sdr_y_nits, hdr_y_nits, metadata->rangeScalingFactor); encodeRecovery(sdr_y_nits, hdr_y_nits, metadata->maxContentBoost); } } } Loading @@ -681,11 +655,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 workers.clear(); hdr_y_nits_avg /= image_width * image_height; metadata->rangeScalingFactor = hdr_y_nits_max / kSdrWhiteNits; if (metadata->transferFunction == JPEGR_TF_PQ) { metadata->hdr10Metadata.maxFALL = hdr_y_nits_avg; metadata->hdr10Metadata.maxCLL = hdr_y_nits_max; } metadata->maxContentBoost = hdr_y_nits_max / kSdrWhiteNits; // generate map jobQueue.reset(); Loading Loading @@ -721,39 +691,21 @@ status_t RecoveryMap::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_ dest->width = uncompressed_yuv_420_image->width; dest->height = uncompressed_yuv_420_image->height; ShepardsIDW idwTable(kMapDimensionScaleFactor); RecoveryLUT recoveryLUT(metadata->rangeScalingFactor); RecoveryLUT recoveryLUT(metadata->maxContentBoost); JobQueue jobQueue; std::function<void()> applyRecMap = [uncompressed_yuv_420_image, uncompressed_recovery_map, metadata, dest, &jobQueue, &idwTable, &recoveryLUT]() -> void { const float hdr_ratio = metadata->rangeScalingFactor; const float hdr_ratio = metadata->maxContentBoost; size_t width = uncompressed_yuv_420_image->width; size_t height = uncompressed_yuv_420_image->height; ColorTransformFn hdrOetf = nullptr; switch (metadata->transferFunction) { case JPEGR_TF_LINEAR: hdrOetf = identityConversion; break; case JPEGR_TF_HLG: #if USE_HLG_OETF_LUT hdrOetf = hlgOetfLUT; #else hdrOetf = hlgOetf; #endif break; case JPEGR_TF_PQ: #if USE_PQ_OETF_LUT hdrOetf = pqOetfLUT; ColorTransformFn hdrOetf = hlgOetfLUT; #else hdrOetf = pqOetf; ColorTransformFn hdrOetf = hlgOetf; #endif break; default: // Should be impossible to hit after input validation. hdrOetf = identityConversion; } size_t rowStart, rowEnd; while (jobQueue.dequeueJob(rowStart, rowEnd)) { Loading Loading @@ -783,7 +735,7 @@ status_t RecoveryMap::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_ #else Color rgb_hdr = applyRecovery(rgb_sdr, recovery, hdr_ratio); #endif Color rgb_gamma_hdr = hdrOetf(rgb_hdr / metadata->rangeScalingFactor); Color rgb_gamma_hdr = hdrOetf(rgb_hdr / metadata->maxContentBoost); uint32_t rgba1010102 = colorToRgba1010102(rgb_gamma_hdr); size_t pixel_idx = x + y * width; Loading libs/jpegrecoverymap/recoverymaputils.cpp +34 −123 Original line number Diff line number Diff line Loading @@ -93,10 +93,8 @@ public: string val; if (gContainerItemState == Started) { if (context.BuildTokenValue(&val)) { if (!val.compare(rangeScalingFactorAttrName)) { lastAttributeName = rangeScalingFactorAttrName; } else if (!val.compare(transferFunctionAttrName)) { lastAttributeName = transferFunctionAttrName; if (!val.compare(maxContentBoostAttrName)) { lastAttributeName = maxContentBoostAttrName; } else { lastAttributeName = ""; } Loading @@ -109,22 +107,20 @@ public: string val; if (gContainerItemState == Started) { if (context.BuildTokenValue(&val, true)) { if (!lastAttributeName.compare(rangeScalingFactorAttrName)) { rangeScalingFactorStr = val; } else if (!lastAttributeName.compare(transferFunctionAttrName)) { transferFunctionStr = val; if (!lastAttributeName.compare(maxContentBoostAttrName)) { maxContentBoostStr = val; } } } return context.GetResult(); } bool getRangeScalingFactor(float* scaling_factor) { bool getMaxContentBoost(float* max_content_boost) { if (gContainerItemState == Done) { stringstream ss(rangeScalingFactorStr); stringstream ss(maxContentBoostStr); float val; if (ss >> val) { *scaling_factor = val; *max_content_boost = val; return true; } else { return false; Loading @@ -134,84 +130,49 @@ public: } } bool getTransferFunction(jpegr_transfer_function* transfer_function) { if (gContainerItemState == Done) { stringstream ss(transferFunctionStr); int val; if (ss >> val) { *transfer_function = static_cast<jpegr_transfer_function>(val); return true; } else { return false; } } else { return false; } return true; } private: static const string gContainerItemName; static const string rangeScalingFactorAttrName; static const string transferFunctionAttrName; string rangeScalingFactorStr; string transferFunctionStr; static const string maxContentBoostAttrName; string maxContentBoostStr; string lastAttributeName; ParseState gContainerItemState; }; // GContainer XMP constants - URI and namespace prefix const string kContainerUri = "http://ns.google.com/photos/1.0/container/"; const string kContainerPrefix = "GContainer"; const string kContainerPrefix = "Container"; // GContainer XMP constants - element and attribute names const string kConDirectory = Name(kContainerPrefix, "Directory"); const string kConItem = Name(kContainerPrefix, "Item"); const string kConItemLength = Name(kContainerPrefix, "ItemLength"); const string kConItemMime = Name(kContainerPrefix, "ItemMime"); const string kConItemSemantic = Name(kContainerPrefix, "ItemSemantic"); const string kConVersion = Name(kContainerPrefix, "Version"); // GContainer XMP constants - element and attribute values // GContainer XMP constants - names for XMP handlers const string XMPXmlHandler::gContainerItemName = kConItem; // Item XMP constants - URI and namespace prefix const string kItemUri = "http://ns.google.com/photos/1.0/container/item/"; const string kItemPrefix = "Item"; // Item XMP constants - element and attribute names const string kItemLength = Name(kItemPrefix, "Length"); const string kItemMime = Name(kItemPrefix, "Mime"); const string kItemSemantic = Name(kItemPrefix, "Semantic"); // Item XMP constants - element and attribute values const string kSemanticPrimary = "Primary"; const string kSemanticRecoveryMap = "RecoveryMap"; const string kMimeImageJpeg = "image/jpeg"; const int kGContainerVersion = 1; // GContainer XMP constants - names for XMP handlers const string XMPXmlHandler::gContainerItemName = kConItem; // RecoveryMap XMP constants - URI and namespace prefix const string kRecoveryMapUri = "http://ns.google.com/photos/1.0/recoverymap/"; const string kRecoveryMapPrefix = "RecoveryMap"; // RecoveryMap XMP constants - element and attribute names const string kMapRangeScalingFactor = Name(kRecoveryMapPrefix, "RangeScalingFactor"); const string kMapTransferFunction = Name(kRecoveryMapPrefix, "TransferFunction"); const string kMapMaxContentBoost = Name(kRecoveryMapPrefix, "MaxContentBoost"); const string kMapVersion = Name(kRecoveryMapPrefix, "Version"); const string kMapHdr10Metadata = Name(kRecoveryMapPrefix, "HDR10Metadata"); const string kMapHdr10MaxFall = Name(kRecoveryMapPrefix, "HDR10MaxFALL"); const string kMapHdr10MaxCll = Name(kRecoveryMapPrefix, "HDR10MaxCLL"); const string kMapSt2086Metadata = Name(kRecoveryMapPrefix, "ST2086Metadata"); const string kMapSt2086MaxLum = Name(kRecoveryMapPrefix, "ST2086MaxLuminance"); const string kMapSt2086MinLum = Name(kRecoveryMapPrefix, "ST2086MinLuminance"); const string kMapSt2086Primary = Name(kRecoveryMapPrefix, "ST2086Primary"); const string kMapSt2086Coordinate = Name(kRecoveryMapPrefix, "ST2086Coordinate"); const string kMapSt2086CoordinateX = Name(kRecoveryMapPrefix, "ST2086CoordinateX"); const string kMapSt2086CoordinateY = Name(kRecoveryMapPrefix, "ST2086CoordinateY"); // RecoveryMap XMP constants - element and attribute values const int kSt2086PrimaryRed = 0; const int kSt2086PrimaryGreen = 1; const int kSt2086PrimaryBlue = 2; const int kSt2086PrimaryWhite = 3; // RecoveryMap XMP constants - names for XMP handlers const string XMPXmlHandler::rangeScalingFactorAttrName = kMapRangeScalingFactor; const string XMPXmlHandler::transferFunctionAttrName = kMapTransferFunction; const string XMPXmlHandler::maxContentBoostAttrName = kMapMaxContentBoost; bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata) { string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; Loading Loading @@ -248,13 +209,10 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta return false; } if (!handler.getRangeScalingFactor(&metadata->rangeScalingFactor)) { if (!handler.getMaxContentBoost(&metadata->maxContentBoost)) { return false; } if (!handler.getTransferFunction(&metadata->transferFunction)) { return false; } return true; } Loading @@ -271,66 +229,19 @@ string generateXmp(int secondary_image_length, jpegr_metadata& metadata) { writer.WriteXmlns("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); writer.StartWritingElement("rdf:Description"); writer.WriteXmlns(kContainerPrefix, kContainerUri); writer.WriteXmlns(kItemPrefix, kItemUri); writer.WriteXmlns(kRecoveryMapPrefix, kRecoveryMapUri); writer.WriteElementAndContent(kConVersion, kGContainerVersion); writer.StartWritingElements(kConDirSeq); size_t item_depth = writer.StartWritingElements(kLiItem); writer.WriteAttributeNameAndValue(kConItemSemantic, kSemanticPrimary); writer.WriteAttributeNameAndValue(kConItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticPrimary); writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kMapVersion, metadata.version); writer.WriteAttributeNameAndValue(kMapRangeScalingFactor, metadata.rangeScalingFactor); writer.WriteAttributeNameAndValue(kMapTransferFunction, metadata.transferFunction); if (metadata.transferFunction == JPEGR_TF_PQ) { writer.StartWritingElement(kMapHdr10Metadata); writer.WriteAttributeNameAndValue(kMapHdr10MaxFall, metadata.hdr10Metadata.maxFALL); writer.WriteAttributeNameAndValue(kMapHdr10MaxCll, metadata.hdr10Metadata.maxCLL); writer.StartWritingElement(kMapSt2086Metadata); writer.WriteAttributeNameAndValue( kMapSt2086MaxLum, metadata.hdr10Metadata.st2086Metadata.maxLuminance); writer.WriteAttributeNameAndValue( kMapSt2086MinLum, metadata.hdr10Metadata.st2086Metadata.minLuminance); // red writer.StartWritingElement(kMapSt2086Coordinate); writer.WriteAttributeNameAndValue(kMapSt2086Primary, kSt2086PrimaryRed); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateX, metadata.hdr10Metadata.st2086Metadata.redPrimary.x); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateY, metadata.hdr10Metadata.st2086Metadata.redPrimary.y); writer.FinishWritingElement(); // green writer.StartWritingElement(kMapSt2086Coordinate); writer.WriteAttributeNameAndValue(kMapSt2086Primary, kSt2086PrimaryGreen); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateX, metadata.hdr10Metadata.st2086Metadata.greenPrimary.x); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateY, metadata.hdr10Metadata.st2086Metadata.greenPrimary.y); writer.FinishWritingElement(); // blue writer.StartWritingElement(kMapSt2086Coordinate); writer.WriteAttributeNameAndValue(kMapSt2086Primary, kSt2086PrimaryBlue); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateX, metadata.hdr10Metadata.st2086Metadata.bluePrimary.x); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateY, metadata.hdr10Metadata.st2086Metadata.bluePrimary.y); writer.FinishWritingElement(); // white writer.StartWritingElement(kMapSt2086Coordinate); writer.WriteAttributeNameAndValue(kMapSt2086Primary, kSt2086PrimaryWhite); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateX, metadata.hdr10Metadata.st2086Metadata.whitePoint.x); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateY, metadata.hdr10Metadata.st2086Metadata.whitePoint.y); writer.FinishWritingElement(); } writer.WriteAttributeNameAndValue(kMapMaxContentBoost, metadata.maxContentBoost); writer.FinishWritingElementsToDepth(item_depth); writer.StartWritingElements(kLiItem); writer.WriteAttributeNameAndValue(kConItemSemantic, kSemanticRecoveryMap); writer.WriteAttributeNameAndValue(kConItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kConItemLength, secondary_image_length); writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticRecoveryMap); writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kItemLength, secondary_image_length); writer.FinishWriting(); return ss.str(); Loading libs/jpegrecoverymap/tests/recoverymap_test.cpp +2 −4 Original line number Diff line number Diff line Loading @@ -103,8 +103,7 @@ TEST_F(RecoveryMapTest, build) { TEST_F(RecoveryMapTest, writeXmpThenRead) { jpegr_metadata metadata_expected; metadata_expected.transferFunction = JPEGR_TF_HLG; metadata_expected.rangeScalingFactor = 1.25; metadata_expected.maxContentBoost = 1.25; int length_expected = 1000; const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator Loading @@ -120,8 +119,7 @@ TEST_F(RecoveryMapTest, writeXmpThenRead) { jpegr_metadata metadata_read; EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read)); ASSERT_EQ(metadata_expected.transferFunction, metadata_read.transferFunction); ASSERT_EQ(metadata_expected.rangeScalingFactor, metadata_read.rangeScalingFactor); ASSERT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost); } /* Test Encode API-0 and decode */ Loading Loading
libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h +8 −42 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ namespace android::recoverymap { // Color gamuts for image data typedef enum { JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT709, Loading @@ -28,7 +29,7 @@ typedef enum { JPEGR_COLORGAMUT_BT2100, } jpegr_color_gamut; // Transfer functions as defined for XMP metadata // Transfer functions for image data typedef enum { JPEGR_TF_UNSPECIFIED = -1, JPEGR_TF_LINEAR = 0, Loading Loading @@ -82,45 +83,11 @@ struct jpegr_exif_struct { int length; }; struct chromaticity_coord { float x; float y; }; struct st2086_metadata { // xy chromaticity coordinate of the red primary of the mastering display chromaticity_coord redPrimary; // xy chromaticity coordinate of the green primary of the mastering display chromaticity_coord greenPrimary; // xy chromaticity coordinate of the blue primary of the mastering display chromaticity_coord bluePrimary; // xy chromaticity coordinate of the white point of the mastering display chromaticity_coord whitePoint; // Maximum luminance in nits of the mastering display uint32_t maxLuminance; // Minimum luminance in nits of the mastering display float minLuminance; }; struct hdr10_metadata { // Mastering display color volume st2086_metadata st2086Metadata; // Max frame average light level in nits float maxFALL; // Max content light level in nits float maxCLL; }; struct jpegr_metadata { // JPEG/R version uint32_t version; // Range scaling factor for the map float rangeScalingFactor; // The transfer function for decoding the HDR representation of the image jpegr_transfer_function transferFunction; // HDR10 metadata, only applicable for transferFunction of JPEGR_TF_PQ hdr10_metadata hdr10Metadata; // Max Content Boost for the map float maxContentBoost; }; typedef struct jpegr_uncompressed_struct* jr_uncompressed_ptr; Loading Loading @@ -270,14 +237,14 @@ private: * * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format * @param uncompressed_p010_image uncompressed HDR image in P010 color format * @param hdr_tf transfer function of the HDR image * @param dest recovery map; caller responsible for memory of data * @param metadata metadata provides the transfer function for the HDR * image; range_scaling_factor and hdr10 FALL and CLL will * be updated. * @param metadata max_content_boost is filled in * @return NO_ERROR if calculation succeeds, error code if error occurs. */ status_t generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, jr_uncompressed_ptr uncompressed_p010_image, jpegr_transfer_function hdr_tf, jr_metadata_ptr metadata, jr_uncompressed_ptr dest); Loading @@ -285,8 +252,7 @@ private: * This method is called in the decoding pipeline. It will take the uncompressed (decoded) * 8-bit yuv image, the uncompressed (decoded) recovery map, and extracted JPEG/R metadata as * input, and calculate the 10-bit recovered image. The recovered output image is the same * color gamut as the SDR image, with the transfer function specified in the JPEG/R metadata, * and is in RGBA1010102 data format. * color gamut as the SDR image, with HLG transfer function, and is in RGBA1010102 data format. * * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format * @param uncompressed_recovery_map uncompressed recovery map Loading
libs/jpegrecoverymap/include/jpegrecoverymap/recoverymaputils.h +14 −19 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta * * below is an example of the XMP metadata that this function generates where * secondary_image_length = 1000 * range_scaling_factor = 1.25 * max_content_boost = 8.0 * * <x:xmpmeta * xmlns:x="adobe:ns:meta/" Loading @@ -63,31 +63,26 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta * <rdf:RDF * xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> * <rdf:Description * xmlns:GContainer="http://ns.google.com/photos/1.0/container/" * xmlns:Container="http://ns.google.com/photos/1.0/container/" * xmlns:Item="http://ns.google.com/photos/1.0/container/item/" * xmlns:RecoveryMap="http://ns.google.com/photos/1.0/recoverymap/"> * <GContainer:Version>1</GContainer:Version> * <GContainer:Directory> * <Container:Directory> * <rdf:Seq> * <rdf:li> * <GContainer:Item * GContainer:ItemSemantic="Primary" * GContainer:ItemMime="image/jpeg" * RecoveryMap:Version=”1” * RecoveryMap:RangeScalingFactor=”1.25” * RecoveryMap:TransferFunction=”2”/> * <RecoveryMap:HDR10Metadata * // some attributes * // some elements * </RecoveryMap:HDR10Metadata> * <Container:Item * Item:Semantic="Primary" * Item:Mime="image/jpeg" * RecoveryMap:Version="1" * RecoveryMap:MaxContentBoost="8.0"/> * </rdf:li> * <rdf:li> * <GContainer:Item * GContainer:ItemSemantic="RecoveryMap" * GContainer:ItemMime="image/jpeg" * GContainer:ItemLength="1000"/> * <Container:Item * Item:Semantic="RecoveryMap" * Item:Mime="image/jpeg" * Item:Length="1000"/> * </rdf:li> * </rdf:Seq> * </GContainer:Directory> * </Container:Directory> * </rdf:Description> * </rdf:RDF> * </x:xmpmeta> Loading
libs/jpegrecoverymap/recoverymap.cpp +15 −63 Original line number Diff line number Diff line Loading @@ -72,16 +72,6 @@ static const size_t kJpegBlock = 8; // JPEG compress quality (0 ~ 100) for recovery map static const int kMapCompressQuality = 85; // TODO: fill in st2086 metadata static const st2086_metadata kSt2086Metadata = { {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.0f, 0.0f}, 0, 1.0f, }; #define CONFIG_MULTITHREAD 1 int GetCPUCoreCount() { int cpuCoreCount = 1; Loading Loading @@ -133,10 +123,6 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_metadata metadata; metadata.version = kJpegrVersion; metadata.transferFunction = hdr_tf; if (hdr_tf == JPEGR_TF_PQ) { metadata.hdr10Metadata.st2086Metadata = kSt2086Metadata; } jpegr_uncompressed_struct uncompressed_yuv_420_image; unique_ptr<uint8_t[]> uncompressed_yuv_420_image_data = make_unique<uint8_t[]>( Loading @@ -146,7 +132,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( &uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); &uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); Loading Loading @@ -207,14 +193,10 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_metadata metadata; metadata.version = kJpegrVersion; metadata.transferFunction = hdr_tf; if (hdr_tf == JPEGR_TF_PQ) { metadata.hdr10Metadata.st2086Metadata = kSt2086Metadata; } jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); Loading Loading @@ -271,14 +253,10 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_metadata metadata; metadata.version = kJpegrVersion; metadata.transferFunction = hdr_tf; if (hdr_tf == JPEGR_TF_PQ) { metadata.hdr10Metadata.st2086Metadata = kSt2086Metadata; } jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); Loading Loading @@ -328,14 +306,10 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_metadata metadata; metadata.version = kJpegrVersion; metadata.transferFunction = hdr_tf; if (hdr_tf == JPEGR_TF_PQ) { metadata.hdr10Metadata.st2086Metadata = kSt2086Metadata; } jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( &uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); &uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); Loading Loading @@ -437,7 +411,6 @@ status_t RecoveryMap::compressRecoveryMap(jr_uncompressed_ptr uncompressed_recov return ERROR_JPEGR_INVALID_NULL_PTR; } // TODO: should we have ICC data for the map? JpegEncoder jpeg_encoder; if (!jpeg_encoder.compressImage(uncompressed_recovery_map->data, uncompressed_recovery_map->width, Loading Loading @@ -518,6 +491,7 @@ void JobQueue::reset() { status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, jr_uncompressed_ptr uncompressed_p010_image, jpegr_transfer_function hdr_tf, jr_metadata_ptr metadata, jr_uncompressed_ptr dest) { if (uncompressed_yuv_420_image == nullptr Loading Loading @@ -554,7 +528,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 ColorTransformFn hdrInvOetf = nullptr; float hdr_white_nits = 0.0f; switch (metadata->transferFunction) { switch (hdr_tf) { case JPEGR_TF_LINEAR: hdrInvOetf = identityConversion; break; Loading Loading @@ -658,7 +632,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 size_t pixel_idx = x + y * dest->width; reinterpret_cast<uint8_t*>(dest->data)[pixel_idx] = encodeRecovery(sdr_y_nits, hdr_y_nits, metadata->rangeScalingFactor); encodeRecovery(sdr_y_nits, hdr_y_nits, metadata->maxContentBoost); } } } Loading @@ -681,11 +655,7 @@ status_t RecoveryMap::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_4 workers.clear(); hdr_y_nits_avg /= image_width * image_height; metadata->rangeScalingFactor = hdr_y_nits_max / kSdrWhiteNits; if (metadata->transferFunction == JPEGR_TF_PQ) { metadata->hdr10Metadata.maxFALL = hdr_y_nits_avg; metadata->hdr10Metadata.maxCLL = hdr_y_nits_max; } metadata->maxContentBoost = hdr_y_nits_max / kSdrWhiteNits; // generate map jobQueue.reset(); Loading Loading @@ -721,39 +691,21 @@ status_t RecoveryMap::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_ dest->width = uncompressed_yuv_420_image->width; dest->height = uncompressed_yuv_420_image->height; ShepardsIDW idwTable(kMapDimensionScaleFactor); RecoveryLUT recoveryLUT(metadata->rangeScalingFactor); RecoveryLUT recoveryLUT(metadata->maxContentBoost); JobQueue jobQueue; std::function<void()> applyRecMap = [uncompressed_yuv_420_image, uncompressed_recovery_map, metadata, dest, &jobQueue, &idwTable, &recoveryLUT]() -> void { const float hdr_ratio = metadata->rangeScalingFactor; const float hdr_ratio = metadata->maxContentBoost; size_t width = uncompressed_yuv_420_image->width; size_t height = uncompressed_yuv_420_image->height; ColorTransformFn hdrOetf = nullptr; switch (metadata->transferFunction) { case JPEGR_TF_LINEAR: hdrOetf = identityConversion; break; case JPEGR_TF_HLG: #if USE_HLG_OETF_LUT hdrOetf = hlgOetfLUT; #else hdrOetf = hlgOetf; #endif break; case JPEGR_TF_PQ: #if USE_PQ_OETF_LUT hdrOetf = pqOetfLUT; ColorTransformFn hdrOetf = hlgOetfLUT; #else hdrOetf = pqOetf; ColorTransformFn hdrOetf = hlgOetf; #endif break; default: // Should be impossible to hit after input validation. hdrOetf = identityConversion; } size_t rowStart, rowEnd; while (jobQueue.dequeueJob(rowStart, rowEnd)) { Loading Loading @@ -783,7 +735,7 @@ status_t RecoveryMap::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_ #else Color rgb_hdr = applyRecovery(rgb_sdr, recovery, hdr_ratio); #endif Color rgb_gamma_hdr = hdrOetf(rgb_hdr / metadata->rangeScalingFactor); Color rgb_gamma_hdr = hdrOetf(rgb_hdr / metadata->maxContentBoost); uint32_t rgba1010102 = colorToRgba1010102(rgb_gamma_hdr); size_t pixel_idx = x + y * width; Loading
libs/jpegrecoverymap/recoverymaputils.cpp +34 −123 Original line number Diff line number Diff line Loading @@ -93,10 +93,8 @@ public: string val; if (gContainerItemState == Started) { if (context.BuildTokenValue(&val)) { if (!val.compare(rangeScalingFactorAttrName)) { lastAttributeName = rangeScalingFactorAttrName; } else if (!val.compare(transferFunctionAttrName)) { lastAttributeName = transferFunctionAttrName; if (!val.compare(maxContentBoostAttrName)) { lastAttributeName = maxContentBoostAttrName; } else { lastAttributeName = ""; } Loading @@ -109,22 +107,20 @@ public: string val; if (gContainerItemState == Started) { if (context.BuildTokenValue(&val, true)) { if (!lastAttributeName.compare(rangeScalingFactorAttrName)) { rangeScalingFactorStr = val; } else if (!lastAttributeName.compare(transferFunctionAttrName)) { transferFunctionStr = val; if (!lastAttributeName.compare(maxContentBoostAttrName)) { maxContentBoostStr = val; } } } return context.GetResult(); } bool getRangeScalingFactor(float* scaling_factor) { bool getMaxContentBoost(float* max_content_boost) { if (gContainerItemState == Done) { stringstream ss(rangeScalingFactorStr); stringstream ss(maxContentBoostStr); float val; if (ss >> val) { *scaling_factor = val; *max_content_boost = val; return true; } else { return false; Loading @@ -134,84 +130,49 @@ public: } } bool getTransferFunction(jpegr_transfer_function* transfer_function) { if (gContainerItemState == Done) { stringstream ss(transferFunctionStr); int val; if (ss >> val) { *transfer_function = static_cast<jpegr_transfer_function>(val); return true; } else { return false; } } else { return false; } return true; } private: static const string gContainerItemName; static const string rangeScalingFactorAttrName; static const string transferFunctionAttrName; string rangeScalingFactorStr; string transferFunctionStr; static const string maxContentBoostAttrName; string maxContentBoostStr; string lastAttributeName; ParseState gContainerItemState; }; // GContainer XMP constants - URI and namespace prefix const string kContainerUri = "http://ns.google.com/photos/1.0/container/"; const string kContainerPrefix = "GContainer"; const string kContainerPrefix = "Container"; // GContainer XMP constants - element and attribute names const string kConDirectory = Name(kContainerPrefix, "Directory"); const string kConItem = Name(kContainerPrefix, "Item"); const string kConItemLength = Name(kContainerPrefix, "ItemLength"); const string kConItemMime = Name(kContainerPrefix, "ItemMime"); const string kConItemSemantic = Name(kContainerPrefix, "ItemSemantic"); const string kConVersion = Name(kContainerPrefix, "Version"); // GContainer XMP constants - element and attribute values // GContainer XMP constants - names for XMP handlers const string XMPXmlHandler::gContainerItemName = kConItem; // Item XMP constants - URI and namespace prefix const string kItemUri = "http://ns.google.com/photos/1.0/container/item/"; const string kItemPrefix = "Item"; // Item XMP constants - element and attribute names const string kItemLength = Name(kItemPrefix, "Length"); const string kItemMime = Name(kItemPrefix, "Mime"); const string kItemSemantic = Name(kItemPrefix, "Semantic"); // Item XMP constants - element and attribute values const string kSemanticPrimary = "Primary"; const string kSemanticRecoveryMap = "RecoveryMap"; const string kMimeImageJpeg = "image/jpeg"; const int kGContainerVersion = 1; // GContainer XMP constants - names for XMP handlers const string XMPXmlHandler::gContainerItemName = kConItem; // RecoveryMap XMP constants - URI and namespace prefix const string kRecoveryMapUri = "http://ns.google.com/photos/1.0/recoverymap/"; const string kRecoveryMapPrefix = "RecoveryMap"; // RecoveryMap XMP constants - element and attribute names const string kMapRangeScalingFactor = Name(kRecoveryMapPrefix, "RangeScalingFactor"); const string kMapTransferFunction = Name(kRecoveryMapPrefix, "TransferFunction"); const string kMapMaxContentBoost = Name(kRecoveryMapPrefix, "MaxContentBoost"); const string kMapVersion = Name(kRecoveryMapPrefix, "Version"); const string kMapHdr10Metadata = Name(kRecoveryMapPrefix, "HDR10Metadata"); const string kMapHdr10MaxFall = Name(kRecoveryMapPrefix, "HDR10MaxFALL"); const string kMapHdr10MaxCll = Name(kRecoveryMapPrefix, "HDR10MaxCLL"); const string kMapSt2086Metadata = Name(kRecoveryMapPrefix, "ST2086Metadata"); const string kMapSt2086MaxLum = Name(kRecoveryMapPrefix, "ST2086MaxLuminance"); const string kMapSt2086MinLum = Name(kRecoveryMapPrefix, "ST2086MinLuminance"); const string kMapSt2086Primary = Name(kRecoveryMapPrefix, "ST2086Primary"); const string kMapSt2086Coordinate = Name(kRecoveryMapPrefix, "ST2086Coordinate"); const string kMapSt2086CoordinateX = Name(kRecoveryMapPrefix, "ST2086CoordinateX"); const string kMapSt2086CoordinateY = Name(kRecoveryMapPrefix, "ST2086CoordinateY"); // RecoveryMap XMP constants - element and attribute values const int kSt2086PrimaryRed = 0; const int kSt2086PrimaryGreen = 1; const int kSt2086PrimaryBlue = 2; const int kSt2086PrimaryWhite = 3; // RecoveryMap XMP constants - names for XMP handlers const string XMPXmlHandler::rangeScalingFactorAttrName = kMapRangeScalingFactor; const string XMPXmlHandler::transferFunctionAttrName = kMapTransferFunction; const string XMPXmlHandler::maxContentBoostAttrName = kMapMaxContentBoost; bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata) { string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; Loading Loading @@ -248,13 +209,10 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta return false; } if (!handler.getRangeScalingFactor(&metadata->rangeScalingFactor)) { if (!handler.getMaxContentBoost(&metadata->maxContentBoost)) { return false; } if (!handler.getTransferFunction(&metadata->transferFunction)) { return false; } return true; } Loading @@ -271,66 +229,19 @@ string generateXmp(int secondary_image_length, jpegr_metadata& metadata) { writer.WriteXmlns("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); writer.StartWritingElement("rdf:Description"); writer.WriteXmlns(kContainerPrefix, kContainerUri); writer.WriteXmlns(kItemPrefix, kItemUri); writer.WriteXmlns(kRecoveryMapPrefix, kRecoveryMapUri); writer.WriteElementAndContent(kConVersion, kGContainerVersion); writer.StartWritingElements(kConDirSeq); size_t item_depth = writer.StartWritingElements(kLiItem); writer.WriteAttributeNameAndValue(kConItemSemantic, kSemanticPrimary); writer.WriteAttributeNameAndValue(kConItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticPrimary); writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kMapVersion, metadata.version); writer.WriteAttributeNameAndValue(kMapRangeScalingFactor, metadata.rangeScalingFactor); writer.WriteAttributeNameAndValue(kMapTransferFunction, metadata.transferFunction); if (metadata.transferFunction == JPEGR_TF_PQ) { writer.StartWritingElement(kMapHdr10Metadata); writer.WriteAttributeNameAndValue(kMapHdr10MaxFall, metadata.hdr10Metadata.maxFALL); writer.WriteAttributeNameAndValue(kMapHdr10MaxCll, metadata.hdr10Metadata.maxCLL); writer.StartWritingElement(kMapSt2086Metadata); writer.WriteAttributeNameAndValue( kMapSt2086MaxLum, metadata.hdr10Metadata.st2086Metadata.maxLuminance); writer.WriteAttributeNameAndValue( kMapSt2086MinLum, metadata.hdr10Metadata.st2086Metadata.minLuminance); // red writer.StartWritingElement(kMapSt2086Coordinate); writer.WriteAttributeNameAndValue(kMapSt2086Primary, kSt2086PrimaryRed); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateX, metadata.hdr10Metadata.st2086Metadata.redPrimary.x); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateY, metadata.hdr10Metadata.st2086Metadata.redPrimary.y); writer.FinishWritingElement(); // green writer.StartWritingElement(kMapSt2086Coordinate); writer.WriteAttributeNameAndValue(kMapSt2086Primary, kSt2086PrimaryGreen); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateX, metadata.hdr10Metadata.st2086Metadata.greenPrimary.x); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateY, metadata.hdr10Metadata.st2086Metadata.greenPrimary.y); writer.FinishWritingElement(); // blue writer.StartWritingElement(kMapSt2086Coordinate); writer.WriteAttributeNameAndValue(kMapSt2086Primary, kSt2086PrimaryBlue); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateX, metadata.hdr10Metadata.st2086Metadata.bluePrimary.x); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateY, metadata.hdr10Metadata.st2086Metadata.bluePrimary.y); writer.FinishWritingElement(); // white writer.StartWritingElement(kMapSt2086Coordinate); writer.WriteAttributeNameAndValue(kMapSt2086Primary, kSt2086PrimaryWhite); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateX, metadata.hdr10Metadata.st2086Metadata.whitePoint.x); writer.WriteAttributeNameAndValue( kMapSt2086CoordinateY, metadata.hdr10Metadata.st2086Metadata.whitePoint.y); writer.FinishWritingElement(); } writer.WriteAttributeNameAndValue(kMapMaxContentBoost, metadata.maxContentBoost); writer.FinishWritingElementsToDepth(item_depth); writer.StartWritingElements(kLiItem); writer.WriteAttributeNameAndValue(kConItemSemantic, kSemanticRecoveryMap); writer.WriteAttributeNameAndValue(kConItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kConItemLength, secondary_image_length); writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticRecoveryMap); writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kItemLength, secondary_image_length); writer.FinishWriting(); return ss.str(); Loading
libs/jpegrecoverymap/tests/recoverymap_test.cpp +2 −4 Original line number Diff line number Diff line Loading @@ -103,8 +103,7 @@ TEST_F(RecoveryMapTest, build) { TEST_F(RecoveryMapTest, writeXmpThenRead) { jpegr_metadata metadata_expected; metadata_expected.transferFunction = JPEGR_TF_HLG; metadata_expected.rangeScalingFactor = 1.25; metadata_expected.maxContentBoost = 1.25; int length_expected = 1000; const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator Loading @@ -120,8 +119,7 @@ TEST_F(RecoveryMapTest, writeXmpThenRead) { jpegr_metadata metadata_read; EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read)); ASSERT_EQ(metadata_expected.transferFunction, metadata_read.transferFunction); ASSERT_EQ(metadata_expected.rangeScalingFactor, metadata_read.rangeScalingFactor); ASSERT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost); } /* Test Encode API-0 and decode */ Loading