Loading libs/jpegrecoverymap/include/jpegrecoverymap/jpegrerrorcode.h +1 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ enum { ERROR_JPEGR_DECODE_ERROR = JPEGR_RUNTIME_ERROR_BASE - 2, ERROR_JPEGR_CALCULATION_ERROR = JPEGR_RUNTIME_ERROR_BASE - 3, ERROR_JPEGR_METADATA_ERROR = JPEGR_RUNTIME_ERROR_BASE - 4, ERROR_JPEGR_TONEMAP_ERROR = JPEGR_RUNTIME_ERROR_BASE - 5, }; } // namespace android::recoverymap libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h +37 −0 Original line number Diff line number Diff line Loading @@ -129,6 +129,28 @@ typedef struct jpegr_info_struct* jr_info_ptr; class RecoveryMap { public: /* * Encode API-0 * Compress JPEGR image from 10-bit HDR YUV. * * Tonemap the HDR input to a SDR image, generate recovery map from the HDR and SDR images, * compress SDR YUV to 8-bit JPEG and append the recovery map to the end of the compressed * JPEG. * @param uncompressed_p010_image uncompressed HDR image in P010 color format * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is * the highest quality * @param exif pointer to the exif metadata. * @return NO_ERROR if encoding succeeds, error code if error occurs. */ status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_transfer_function hdr_tf, jr_compressed_ptr dest, int quality, jr_exif_ptr exif); /* * Encode API-1 * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV. * * Generate recovery map from the HDR and SDR inputs, compress SDR YUV to 8-bit JPEG and append Loading @@ -151,6 +173,7 @@ public: jr_exif_ptr exif); /* * Encode API-2 * Compress JPEGR image from 10-bit HDR YUV, 8-bit SDR YUV and compressed 8-bit JPEG. * * This method requires HAL Hardware JPEG encoder. Loading @@ -159,6 +182,8 @@ public: * compressed JPEG. HDR and SDR inputs must be the same resolution and color space. * @param uncompressed_p010_image uncompressed HDR image in P010 color format * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format * Note: the SDR image must be the decoded version of the JPEG * input * @param compressed_jpeg_image compressed 8-bit JPEG image * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image Loading @@ -171,6 +196,7 @@ public: jr_compressed_ptr dest); /* * Encode API-3 * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV. * * This method requires HAL Hardware JPEG encoder. Loading @@ -190,6 +216,7 @@ public: jr_compressed_ptr dest); /* * Decode API * Decompress JPEGR image. * * The output JPEGR image is in RGBA_1010102 data format if decoding to HDR. Loading Loading @@ -356,6 +383,16 @@ private: * @return XMP metadata in type of string */ std::string generateXmp(int secondary_image_length, jpegr_metadata& metadata); /* * This method will tone map a HDR image to an SDR image. * * @param uncompressed_p010_image (input) uncompressed P010 image * @param dest (output) tone mapping result as a YUV_420 image * @return NO_ERROR if calculation succeeds, error code if error occurs. */ status_t toneMap(jr_uncompressed_ptr uncompressed_p010_image, jr_uncompressed_ptr dest); }; } // namespace android::recoverymap Loading libs/jpegrecoverymap/recoverymap.cpp +72 −1 Original line number Diff line number Diff line Loading @@ -96,6 +96,59 @@ status_t Write(jr_compressed_ptr destination, const void* source, size_t length, return NO_ERROR; } /* Encode API-0 */ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_transfer_function hdr_tf, jr_compressed_ptr dest, int quality, jr_exif_ptr /* exif */) { if (uncompressed_p010_image == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } if (quality < 0 || quality > 100) { return ERROR_JPEGR_INVALID_INPUT_TYPE; } 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; JPEGR_CHECK(toneMap(uncompressed_p010_image, &uncompressed_yuv_420_image)); jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( &uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); jpegr_compressed_struct compressed_map; compressed_map.maxLength = map.width * map.height; unique_ptr<uint8_t[]> compressed_map_data = make_unique<uint8_t[]>(compressed_map.maxLength); compressed_map.data = compressed_map_data.get(); JPEGR_CHECK(compressRecoveryMap(&map, &compressed_map)); JpegEncoder jpeg_encoder; // TODO: determine ICC data based on color gamut information if (!jpeg_encoder.compressImage(uncompressed_yuv_420_image.data, uncompressed_yuv_420_image.width, uncompressed_yuv_420_image.height, quality, nullptr, 0)) { return ERROR_JPEGR_ENCODE_ERROR; } jpegr_compressed_struct jpeg; jpeg.data = jpeg_encoder.getCompressedImagePtr(); jpeg.length = jpeg_encoder.getCompressedImageSize(); JPEGR_CHECK(appendRecoveryMap(&jpeg, &compressed_map, &metadata, dest)); return NO_ERROR; } /* Encode API-1 */ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jr_uncompressed_ptr uncompressed_yuv_420_image, jpegr_transfer_function hdr_tf, Loading Loading @@ -152,6 +205,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, return NO_ERROR; } /* Encode API-2 */ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jr_uncompressed_ptr uncompressed_yuv_420_image, jr_compressed_ptr compressed_jpeg_image, Loading Loading @@ -193,6 +247,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, return NO_ERROR; } /* Encode API-3 */ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jr_compressed_ptr compressed_jpeg_image, jpegr_transfer_function hdr_tf, Loading Loading @@ -262,7 +317,7 @@ status_t RecoveryMap::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, return NO_ERROR; } /* Decode API */ status_t RecoveryMap::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, jr_uncompressed_ptr dest, jr_exif_ptr exif, Loading Loading @@ -676,4 +731,20 @@ string RecoveryMap::generateXmp(int secondary_image_length, jpegr_metadata& meta return ss.str(); } status_t RecoveryMap::toneMap(jr_uncompressed_ptr uncompressed_p010_image, jr_uncompressed_ptr dest) { if (uncompressed_p010_image == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } dest->width = uncompressed_p010_image->width; dest->height = uncompressed_p010_image->height; unique_ptr<uint8_t[]> dest_data = make_unique<uint8_t[]>(dest->width * dest->height * 3 / 2); dest->data = dest_data.get(); // TODO: Tone map algorighm here. return NO_ERROR; } } // namespace android::recoverymap libs/jpegrecoverymap/tests/recoverymap_test.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ static bool loadFile(const char filename[], void*& result, int* fileLength) { TEST_F(RecoveryMapTest, build) { // Force all of the recovery map lib to be linked by calling all public functions. RecoveryMap recovery_map; recovery_map.encodeJPEGR(nullptr, static_cast<jpegr_transfer_function>(0), nullptr, 0, nullptr); recovery_map.encodeJPEGR(nullptr, nullptr, static_cast<jpegr_transfer_function>(0), nullptr, 0, nullptr); recovery_map.encodeJPEGR(nullptr, nullptr, nullptr, static_cast<jpegr_transfer_function>(0), Loading Loading
libs/jpegrecoverymap/include/jpegrecoverymap/jpegrerrorcode.h +1 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ enum { ERROR_JPEGR_DECODE_ERROR = JPEGR_RUNTIME_ERROR_BASE - 2, ERROR_JPEGR_CALCULATION_ERROR = JPEGR_RUNTIME_ERROR_BASE - 3, ERROR_JPEGR_METADATA_ERROR = JPEGR_RUNTIME_ERROR_BASE - 4, ERROR_JPEGR_TONEMAP_ERROR = JPEGR_RUNTIME_ERROR_BASE - 5, }; } // namespace android::recoverymap
libs/jpegrecoverymap/include/jpegrecoverymap/recoverymap.h +37 −0 Original line number Diff line number Diff line Loading @@ -129,6 +129,28 @@ typedef struct jpegr_info_struct* jr_info_ptr; class RecoveryMap { public: /* * Encode API-0 * Compress JPEGR image from 10-bit HDR YUV. * * Tonemap the HDR input to a SDR image, generate recovery map from the HDR and SDR images, * compress SDR YUV to 8-bit JPEG and append the recovery map to the end of the compressed * JPEG. * @param uncompressed_p010_image uncompressed HDR image in P010 color format * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is * the highest quality * @param exif pointer to the exif metadata. * @return NO_ERROR if encoding succeeds, error code if error occurs. */ status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_transfer_function hdr_tf, jr_compressed_ptr dest, int quality, jr_exif_ptr exif); /* * Encode API-1 * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV. * * Generate recovery map from the HDR and SDR inputs, compress SDR YUV to 8-bit JPEG and append Loading @@ -151,6 +173,7 @@ public: jr_exif_ptr exif); /* * Encode API-2 * Compress JPEGR image from 10-bit HDR YUV, 8-bit SDR YUV and compressed 8-bit JPEG. * * This method requires HAL Hardware JPEG encoder. Loading @@ -159,6 +182,8 @@ public: * compressed JPEG. HDR and SDR inputs must be the same resolution and color space. * @param uncompressed_p010_image uncompressed HDR image in P010 color format * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format * Note: the SDR image must be the decoded version of the JPEG * input * @param compressed_jpeg_image compressed 8-bit JPEG image * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image Loading @@ -171,6 +196,7 @@ public: jr_compressed_ptr dest); /* * Encode API-3 * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV. * * This method requires HAL Hardware JPEG encoder. Loading @@ -190,6 +216,7 @@ public: jr_compressed_ptr dest); /* * Decode API * Decompress JPEGR image. * * The output JPEGR image is in RGBA_1010102 data format if decoding to HDR. Loading Loading @@ -356,6 +383,16 @@ private: * @return XMP metadata in type of string */ std::string generateXmp(int secondary_image_length, jpegr_metadata& metadata); /* * This method will tone map a HDR image to an SDR image. * * @param uncompressed_p010_image (input) uncompressed P010 image * @param dest (output) tone mapping result as a YUV_420 image * @return NO_ERROR if calculation succeeds, error code if error occurs. */ status_t toneMap(jr_uncompressed_ptr uncompressed_p010_image, jr_uncompressed_ptr dest); }; } // namespace android::recoverymap Loading
libs/jpegrecoverymap/recoverymap.cpp +72 −1 Original line number Diff line number Diff line Loading @@ -96,6 +96,59 @@ status_t Write(jr_compressed_ptr destination, const void* source, size_t length, return NO_ERROR; } /* Encode API-0 */ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jpegr_transfer_function hdr_tf, jr_compressed_ptr dest, int quality, jr_exif_ptr /* exif */) { if (uncompressed_p010_image == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } if (quality < 0 || quality > 100) { return ERROR_JPEGR_INVALID_INPUT_TYPE; } 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; JPEGR_CHECK(toneMap(uncompressed_p010_image, &uncompressed_yuv_420_image)); jpegr_uncompressed_struct map; JPEGR_CHECK(generateRecoveryMap( &uncompressed_yuv_420_image, uncompressed_p010_image, &metadata, &map)); std::unique_ptr<uint8_t[]> map_data; map_data.reset(reinterpret_cast<uint8_t*>(map.data)); jpegr_compressed_struct compressed_map; compressed_map.maxLength = map.width * map.height; unique_ptr<uint8_t[]> compressed_map_data = make_unique<uint8_t[]>(compressed_map.maxLength); compressed_map.data = compressed_map_data.get(); JPEGR_CHECK(compressRecoveryMap(&map, &compressed_map)); JpegEncoder jpeg_encoder; // TODO: determine ICC data based on color gamut information if (!jpeg_encoder.compressImage(uncompressed_yuv_420_image.data, uncompressed_yuv_420_image.width, uncompressed_yuv_420_image.height, quality, nullptr, 0)) { return ERROR_JPEGR_ENCODE_ERROR; } jpegr_compressed_struct jpeg; jpeg.data = jpeg_encoder.getCompressedImagePtr(); jpeg.length = jpeg_encoder.getCompressedImageSize(); JPEGR_CHECK(appendRecoveryMap(&jpeg, &compressed_map, &metadata, dest)); return NO_ERROR; } /* Encode API-1 */ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jr_uncompressed_ptr uncompressed_yuv_420_image, jpegr_transfer_function hdr_tf, Loading Loading @@ -152,6 +205,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, return NO_ERROR; } /* Encode API-2 */ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jr_uncompressed_ptr uncompressed_yuv_420_image, jr_compressed_ptr compressed_jpeg_image, Loading Loading @@ -193,6 +247,7 @@ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, return NO_ERROR; } /* Encode API-3 */ status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, jr_compressed_ptr compressed_jpeg_image, jpegr_transfer_function hdr_tf, Loading Loading @@ -262,7 +317,7 @@ status_t RecoveryMap::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, return NO_ERROR; } /* Decode API */ status_t RecoveryMap::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, jr_uncompressed_ptr dest, jr_exif_ptr exif, Loading Loading @@ -676,4 +731,20 @@ string RecoveryMap::generateXmp(int secondary_image_length, jpegr_metadata& meta return ss.str(); } status_t RecoveryMap::toneMap(jr_uncompressed_ptr uncompressed_p010_image, jr_uncompressed_ptr dest) { if (uncompressed_p010_image == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } dest->width = uncompressed_p010_image->width; dest->height = uncompressed_p010_image->height; unique_ptr<uint8_t[]> dest_data = make_unique<uint8_t[]>(dest->width * dest->height * 3 / 2); dest->data = dest_data.get(); // TODO: Tone map algorighm here. return NO_ERROR; } } // namespace android::recoverymap
libs/jpegrecoverymap/tests/recoverymap_test.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -85,6 +85,7 @@ static bool loadFile(const char filename[], void*& result, int* fileLength) { TEST_F(RecoveryMapTest, build) { // Force all of the recovery map lib to be linked by calling all public functions. RecoveryMap recovery_map; recovery_map.encodeJPEGR(nullptr, static_cast<jpegr_transfer_function>(0), nullptr, 0, nullptr); recovery_map.encodeJPEGR(nullptr, nullptr, static_cast<jpegr_transfer_function>(0), nullptr, 0, nullptr); recovery_map.encodeJPEGR(nullptr, nullptr, nullptr, static_cast<jpegr_transfer_function>(0), Loading