aboutsummaryrefslogtreecommitdiff
path: root/lib/src
diff options
context:
space:
mode:
authorHarish Mahendrakar <hmahendrakar@google.com>2024-01-10 02:18:45 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2024-01-10 02:18:45 +0000
commitcef2e104a50bace03d615e2cf353358212c8e129 (patch)
tree576b365c6d49a8c1b2813807391e49dcc8f54cb3 /lib/src
parent5d7f30ac00a5b92fca6656629c995cc0fd0087f4 (diff)
parent2b41c0a1c9e4f4131ee7c77f486cac2e18d260b0 (diff)
downloadlibultrahdr-cef2e104a50bace03d615e2cf353358212c8e129.tar.gz
Upgrade libultrahdr to 3f9c0ec5590c2fa47b78a8bc125ca5e6b27e5728 am: 38297ba7bd am: 1155fa684f am: 2b41c0a1c9
Original change: https://android-review.googlesource.com/c/platform/external/libultrahdr/+/2901097 Change-Id: I8f4b8190972298c786547f16533b91357df868b2 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'lib/src')
-rw-r--r--lib/src/icc.cpp7
-rw-r--r--lib/src/jpegdecoderhelper.cpp81
-rw-r--r--lib/src/jpegr.cpp117
-rw-r--r--lib/src/jpegrutils.cpp30
4 files changed, 130 insertions, 105 deletions
diff --git a/lib/src/icc.cpp b/lib/src/icc.cpp
index b838660..0b4b341 100644
--- a/lib/src/icc.cpp
+++ b/lib/src/icc.cpp
@@ -633,6 +633,13 @@ ultrahdr_color_gamut IccHelper::readIccColorGamut(void* icc_data, size_t icc_siz
size_t red_primary_offset = 0, green_primary_offset = 0, blue_primary_offset = 0;
size_t red_primary_size = 0, green_primary_size = 0, blue_primary_size = 0;
for (size_t tag_idx = 0; tag_idx < Endian_SwapBE32(header->tag_count); ++tag_idx) {
+ if (icc_size < kICCIdentifierSize + sizeof(ICCHeader) + ((tag_idx + 1) * kTagTableEntrySize)) {
+ ALOGE(
+ "Insufficient buffer size during icc parsing. tag index %zu, header %zu, tag size %zu, "
+ "icc size %zu",
+ tag_idx, kICCIdentifierSize + sizeof(ICCHeader), kTagTableEntrySize, icc_size);
+ return ULTRAHDR_COLORGAMUT_UNSPECIFIED;
+ }
uint32_t* tag_entry_start =
reinterpret_cast<uint32_t*>(icc_bytes + sizeof(ICCHeader) + tag_idx * kTagTableEntrySize);
// first 4 bytes are the tag signature, next 4 bytes are the tag offset,
diff --git a/lib/src/jpegdecoderhelper.cpp b/lib/src/jpegdecoderhelper.cpp
index 8a8278d..70efb87 100644
--- a/lib/src/jpegdecoderhelper.cpp
+++ b/lib/src/jpegdecoderhelper.cpp
@@ -108,14 +108,14 @@ JpegDecoderHelper::JpegDecoderHelper() {}
JpegDecoderHelper::~JpegDecoderHelper() {}
-bool JpegDecoderHelper::decompressImage(const void* image, int length, bool decodeToRGBA) {
+bool JpegDecoderHelper::decompressImage(const void* image, int length, decode_mode_t decodeTo) {
if (image == nullptr || length <= 0) {
ALOGE("Image size can not be handled: %d", length);
return false;
}
mResultBuffer.clear();
mXMPBuffer.clear();
- return decode(image, length, decodeToRGBA);
+ return decode(image, length, decodeTo);
}
void* JpegDecoderHelper::getDecompressedImagePtr() { return mResultBuffer.data(); }
@@ -187,7 +187,7 @@ bool JpegDecoderHelper::extractEXIF(const void* image, int length) {
return true;
}
-bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) {
+bool JpegDecoderHelper::decode(const void* image, int length, decode_mode_t decodeTo) {
bool status = true;
jpeg_decompress_struct cinfo;
jpegrerror_mgr myerr;
@@ -256,7 +256,7 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA)
goto CleanUp;
}
- if (decodeToRGBA) {
+ if (decodeTo == DECODE_TO_RGBA) {
// The primary image is expected to be yuv420 sampling
if (cinfo.jpeg_color_space != JCS_YCbCr) {
status = false;
@@ -273,7 +273,7 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA)
// 4 bytes per pixel
mResultBuffer.resize(cinfo.image_width * cinfo.image_height * 4);
cinfo.out_color_space = JCS_EXT_RGBA;
- } else {
+ } else if (decodeTo == DECODE_TO_YCBCR) {
if (cinfo.jpeg_color_space == JCS_YCbCr) {
if (cinfo.comp_info[0].h_samp_factor != 2 || cinfo.comp_info[0].v_samp_factor != 2 ||
cinfo.comp_info[1].h_samp_factor != 1 || cinfo.comp_info[1].v_samp_factor != 1 ||
@@ -292,6 +292,10 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA)
}
cinfo.out_color_space = cinfo.jpeg_color_space;
cinfo.raw_data_out = TRUE;
+ } else {
+ status = decodeTo == PARSE_ONLY;
+ jpeg_destroy_decompress(&cinfo);
+ return status;
}
cinfo.dct_method = JDCT_ISLOW;
@@ -316,71 +320,8 @@ bool JpegDecoderHelper::decompress(jpeg_decompress_struct* cinfo, const uint8_t*
: decompressYUV(cinfo, dest));
}
-bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int length, size_t* pWidth,
- size_t* pHeight, std::vector<uint8_t>* iccData,
- std::vector<uint8_t>* exifData) {
- jpeg_decompress_struct cinfo;
- jpegrerror_mgr myerr;
- cinfo.err = jpeg_std_error(&myerr.pub);
- myerr.pub.error_exit = jpegrerror_exit;
- myerr.pub.output_message = output_message;
-
- if (setjmp(myerr.setjmp_buffer)) {
- jpeg_destroy_decompress(&cinfo);
- return false;
- }
- jpeg_create_decompress(&cinfo);
-
- jpeg_save_markers(&cinfo, kAPP1Marker, 0xFFFF);
- jpeg_save_markers(&cinfo, kAPP2Marker, 0xFFFF);
-
- jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
- cinfo.src = &mgr;
- if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
- jpeg_destroy_decompress(&cinfo);
- return false;
- }
-
- if (pWidth != nullptr) {
- *pWidth = cinfo.image_width;
- }
- if (pHeight != nullptr) {
- *pHeight = cinfo.image_height;
- }
-
- if (iccData != nullptr) {
- for (jpeg_marker_struct* marker = cinfo.marker_list; marker; marker = marker->next) {
- if (marker->marker != kAPP2Marker) {
- continue;
- }
- if (marker->data_length <= kICCMarkerHeaderSize ||
- memcmp(marker->data, kICCSig, sizeof(kICCSig)) != 0) {
- continue;
- }
-
- iccData->insert(iccData->end(), marker->data, marker->data + marker->data_length);
- }
- }
-
- if (exifData != nullptr) {
- bool exifAppears = false;
- for (jpeg_marker_struct* marker = cinfo.marker_list; marker && !exifAppears;
- marker = marker->next) {
- if (marker->marker != kAPP1Marker) {
- continue;
- }
-
- const unsigned int len = marker->data_length;
- if (len >= sizeof(kExifIdCode) && !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) {
- exifData->resize(len, 0);
- memcpy(static_cast<void*>(exifData->data()), marker->data, len);
- exifAppears = true;
- }
- }
- }
-
- jpeg_destroy_decompress(&cinfo);
- return true;
+bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int length) {
+ return decode(image, length, PARSE_ONLY);
}
bool JpegDecoderHelper::decompressRGBA(jpeg_decompress_struct* cinfo, const uint8_t* dest) {
diff --git a/lib/src/jpegr.cpp b/lib/src/jpegr.cpp
index ed4fef1..74ef134 100644
--- a/lib/src/jpegr.cpp
+++ b/lib/src/jpegr.cpp
@@ -558,13 +558,13 @@ status_t JpegR::encodeJPEGR(jr_compressed_ptr yuv420jpg_image_ptr,
// We just want to check if ICC is present, so don't do a full decode. Note,
// this doesn't verify that the ICC is valid.
JpegDecoderHelper decoder;
- std::vector<uint8_t> icc;
- decoder.getCompressedImageParameters(yuv420jpg_image_ptr->data, yuv420jpg_image_ptr->length,
- /* pWidth */ nullptr, /* pHeight */ nullptr, &icc,
- /* exifData */ nullptr);
+ if (!decoder.getCompressedImageParameters(yuv420jpg_image_ptr->data,
+ yuv420jpg_image_ptr->length)) {
+ return ERROR_JPEGR_DECODE_ERROR;
+ }
// Add ICC if not already present.
- if (icc.size() > 0) {
+ if (decoder.getICCSize() > 0) {
JPEGR_CHECK(appendGainMap(yuv420jpg_image_ptr, gainmapjpg_image_ptr, /* exif */ nullptr,
/* icc */ nullptr, /* icc size */ 0, metadata, dest));
} else {
@@ -577,12 +577,12 @@ status_t JpegR::encodeJPEGR(jr_compressed_ptr yuv420jpg_image_ptr,
return JPEGR_NO_ERROR;
}
-status_t JpegR::getJPEGRInfo(jr_compressed_ptr jpegr_image_ptr, jr_info_ptr jpeg_image_info_ptr) {
+status_t JpegR::getJPEGRInfo(jr_compressed_ptr jpegr_image_ptr, jr_info_ptr jpegr_image_info_ptr) {
if (jpegr_image_ptr == nullptr || jpegr_image_ptr->data == nullptr) {
ALOGE("received nullptr for compressed jpegr image");
return ERROR_JPEGR_BAD_PTR;
}
- if (jpeg_image_info_ptr == nullptr) {
+ if (jpegr_image_info_ptr == nullptr) {
ALOGE("received nullptr for compressed jpegr info struct");
return ERROR_JPEGR_BAD_PTR;
}
@@ -592,13 +592,16 @@ status_t JpegR::getJPEGRInfo(jr_compressed_ptr jpegr_image_ptr, jr_info_ptr jpeg
if (status != JPEGR_NO_ERROR && status != ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND) {
return status;
}
-
- JpegDecoderHelper jpeg_dec_obj_hdr;
- if (!jpeg_dec_obj_hdr.getCompressedImageParameters(
- primary_image.data, primary_image.length, &jpeg_image_info_ptr->width,
- &jpeg_image_info_ptr->height, jpeg_image_info_ptr->iccData,
- jpeg_image_info_ptr->exifData)) {
- return ERROR_JPEGR_DECODE_ERROR;
+ status = parseJpegInfo(&primary_image, jpegr_image_info_ptr->primaryImgInfo,
+ &jpegr_image_info_ptr->width, &jpegr_image_info_ptr->height);
+ if (status != JPEGR_NO_ERROR) {
+ return status;
+ }
+ if (jpegr_image_info_ptr->gainmapImgInfo != nullptr) {
+ status = parseJpegInfo(&gainmap_image, jpegr_image_info_ptr->gainmapImgInfo);
+ if (status != JPEGR_NO_ERROR) {
+ return status;
+ }
}
return status;
@@ -641,8 +644,9 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr jpegr_image_ptr, jr_uncompressed_p
}
JpegDecoderHelper jpeg_dec_obj_yuv420;
- if (!jpeg_dec_obj_yuv420.decompressImage(primary_jpeg_image.data, primary_jpeg_image.length,
- (output_format == ULTRAHDR_OUTPUT_SDR))) {
+ if (!jpeg_dec_obj_yuv420.decompressImage(
+ primary_jpeg_image.data, primary_jpeg_image.length,
+ (output_format == ULTRAHDR_OUTPUT_SDR) ? DECODE_TO_RGBA : DECODE_TO_YCBCR)) {
return ERROR_JPEGR_DECODE_ERROR;
}
@@ -1010,29 +1014,39 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr,
return ERROR_JPEGR_BAD_METADATA;
}
- // TODO: remove once map scaling factor is computed based on actual map dims
- size_t image_width = yuv420_image_ptr->width;
- size_t image_height = yuv420_image_ptr->height;
- size_t map_width = image_width / kMapDimensionScaleFactor;
- size_t map_height = image_height / kMapDimensionScaleFactor;
- if (map_width != gainmap_image_ptr->width || map_height != gainmap_image_ptr->height) {
+ if (yuv420_image_ptr->width % gainmap_image_ptr->width != 0 ||
+ yuv420_image_ptr->height % gainmap_image_ptr->height != 0) {
ALOGE(
- "gain map dimensions and primary image dimensions are not to scale, computed gain map "
- "resolution is %zux%zu, received gain map resolution is %zux%zu",
- map_width, map_height, gainmap_image_ptr->width, gainmap_image_ptr->height);
- return ERROR_JPEGR_RESOLUTION_MISMATCH;
+ "gain map dimensions scale factor value is not an integer, primary image resolution is "
+ "%zux%zu, received gain map resolution is %zux%zu",
+ yuv420_image_ptr->width, yuv420_image_ptr->height, gainmap_image_ptr->width,
+ gainmap_image_ptr->height);
+ return ERROR_JPEGR_UNSUPPORTED_MAP_SCALE_FACTOR;
}
+ if (yuv420_image_ptr->width * gainmap_image_ptr->height !=
+ yuv420_image_ptr->height * gainmap_image_ptr->width) {
+ ALOGE(
+ "gain map dimensions scale factor values for height and width are different, \n primary "
+ "image resolution is %zux%zu, received gain map resolution is %zux%zu",
+ yuv420_image_ptr->width, yuv420_image_ptr->height, gainmap_image_ptr->width,
+ gainmap_image_ptr->height);
+ return ERROR_JPEGR_UNSUPPORTED_MAP_SCALE_FACTOR;
+ }
+ // TODO: Currently map_scale_factor is of type size_t, but it could be changed to a float
+ // later.
+ size_t map_scale_factor = yuv420_image_ptr->width / gainmap_image_ptr->width;
+
dest->width = yuv420_image_ptr->width;
dest->height = yuv420_image_ptr->height;
- ShepardsIDW idwTable(kMapDimensionScaleFactor);
+ ShepardsIDW idwTable(map_scale_factor);
float display_boost = (std::min)(max_display_boost, metadata->maxContentBoost);
GainLUT gainLUT(metadata, display_boost);
JobQueue jobQueue;
std::function<void()> applyRecMap = [yuv420_image_ptr, gainmap_image_ptr, dest, &jobQueue,
- &idwTable, output_format, &gainLUT,
- display_boost]() -> void {
+ &idwTable, output_format, &gainLUT, display_boost,
+ map_scale_factor]() -> void {
size_t width = yuv420_image_ptr->width;
size_t rowStart, rowEnd;
@@ -1049,11 +1063,7 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr,
Color rgb_sdr = srgbInvOetf(rgb_gamma_sdr);
#endif
float gain;
- // TODO: determine map scaling factor based on actual map dims
- size_t map_scale_factor = kMapDimensionScaleFactor;
// TODO: If map_scale_factor is guaranteed to be an integer, then remove the following.
- // Currently map_scale_factor is of type size_t, but it could be changed to a float
- // later.
if (map_scale_factor != floorf(map_scale_factor)) {
gain = sampleMap(gainmap_image_ptr, map_scale_factor, x, y);
} else {
@@ -1110,7 +1120,7 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr,
for (int th = 0; th < threads - 1; th++) {
workers.push_back(std::thread(applyRecMap));
}
- const int rowStep = threads == 1 ? yuv420_image_ptr->height : kJobSzInRows;
+ const int rowStep = threads == 1 ? yuv420_image_ptr->height : map_scale_factor;
for (size_t rowStart = 0; rowStart < yuv420_image_ptr->height;) {
int rowEnd = (std::min)(rowStart + rowStep, yuv420_image_ptr->height);
jobQueue.enqueueJob(rowStart, rowEnd);
@@ -1177,6 +1187,45 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr,
return JPEGR_NO_ERROR;
}
+status_t JpegR::parseJpegInfo(jr_compressed_ptr jpeg_image_ptr, j_info_ptr jpeg_image_info_ptr,
+ size_t* img_width, size_t* img_height) {
+ JpegDecoderHelper jpeg_dec_obj;
+ if (!jpeg_dec_obj.getCompressedImageParameters(jpeg_image_ptr->data, jpeg_image_ptr->length)) {
+ return ERROR_JPEGR_DECODE_ERROR;
+ }
+ size_t imgWidth, imgHeight;
+ imgWidth = jpeg_dec_obj.getDecompressedImageWidth();
+ imgHeight = jpeg_dec_obj.getDecompressedImageHeight();
+
+ if (jpeg_image_info_ptr != nullptr) {
+ jpeg_image_info_ptr->width = imgWidth;
+ jpeg_image_info_ptr->height = imgHeight;
+ jpeg_image_info_ptr->imgData.resize(jpeg_image_ptr->length, 0);
+ memcpy(static_cast<void*>(jpeg_image_info_ptr->imgData.data()), jpeg_image_ptr->data,
+ jpeg_image_ptr->length);
+ if (jpeg_dec_obj.getICCSize() != 0) {
+ jpeg_image_info_ptr->iccData.resize(jpeg_dec_obj.getICCSize(), 0);
+ memcpy(static_cast<void*>(jpeg_image_info_ptr->iccData.data()), jpeg_dec_obj.getICCPtr(),
+ jpeg_dec_obj.getICCSize());
+ }
+ if (jpeg_dec_obj.getEXIFSize() != 0) {
+ jpeg_image_info_ptr->exifData.resize(jpeg_dec_obj.getEXIFSize(), 0);
+ memcpy(static_cast<void*>(jpeg_image_info_ptr->exifData.data()), jpeg_dec_obj.getEXIFPtr(),
+ jpeg_dec_obj.getEXIFSize());
+ }
+ if (jpeg_dec_obj.getXMPSize() != 0) {
+ jpeg_image_info_ptr->xmpData.resize(jpeg_dec_obj.getXMPSize(), 0);
+ memcpy(static_cast<void*>(jpeg_image_info_ptr->xmpData.data()), jpeg_dec_obj.getXMPPtr(),
+ jpeg_dec_obj.getXMPSize());
+ }
+ }
+ if (img_width != nullptr && img_height != nullptr) {
+ *img_width = imgWidth;
+ *img_height = imgHeight;
+ }
+ return JPEGR_NO_ERROR;
+}
+
// JPEG/R structure:
// SOI (ff d8)
//
diff --git a/lib/src/jpegrutils.cpp b/lib/src/jpegrutils.cpp
index 77cb26b..bfc847f 100644
--- a/lib/src/jpegrutils.cpp
+++ b/lib/src/jpegrutils.cpp
@@ -451,7 +451,35 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, ultrahdr_metadata_st
xmp_size -= nameSpace.size() + 1;
XMPXmlHandler handler;
- // We need to remove tail data until the closing tag. Otherwise parser will throw an error.
+ // xml parser fails to parse packet header, wrapper. remove them before handing the data to
+ // parser. if there is no packet header, do nothing otherwise go to the position of '<' without
+ // '?' after it.
+ int offset = 0;
+ for (int i = 0; i < xmp_size; ++i) {
+ if (xmp_data[i] == '<') {
+ if (xmp_data[i + 1] != '?') {
+ offset = i;
+ break;
+ }
+ }
+ }
+ xmp_data += offset;
+ xmp_size -= offset;
+
+ // If there is no packet wrapper, do nothing other wise go to the position of last '>' without '?'
+ // before it.
+ offset = 0;
+ for (int i = xmp_size - 1; i >= 1; --i) {
+ if (xmp_data[i] == '>') {
+ if (xmp_data[i - 1] != '?') {
+ offset = xmp_size - (i + 1);
+ break;
+ }
+ }
+ }
+ xmp_size -= offset;
+
+ // remove padding
while (xmp_data[xmp_size - 1] != '>' && xmp_size > 1) {
xmp_size--;
}