aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarish Mahendrakar <hmahendrakar@google.com>2024-01-09 05:07:46 +0000
committerHarish Mahendrakar <hmahendrakar@google.com>2024-01-09 05:16:20 +0000
commit38297ba7bd6a5adc71121bfc8e970b0424c119cf (patch)
tree576b365c6d49a8c1b2813807391e49dcc8f54cb3
parentbe91e199aec3c67f8a4a0263d6b97d353896c94c (diff)
parent3f9c0ec5590c2fa47b78a8bc125ca5e6b27e5728 (diff)
downloadlibultrahdr-simpleperf-release.tar.gz
Upgrade libultrahdr to 3f9c0ec5590c2fa47b78a8bc125ca5e6b27e5728simpleperf-release
This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update libultrahdr For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md Bug: 319187412 Test: TreeHugger Change-Id: Ia04c8b9aa66ac4de802df020a9ca4ee078876194
-rw-r--r--CMakeLists.txt47
-rw-r--r--METADATA16
-rw-r--r--README.md30
-rw-r--r--benchmark/Android.bp2
-rw-r--r--benchmark/AndroidTest.xml37
-rw-r--r--benchmark/DynamicConfig.xml20
-rw-r--r--benchmark/benchmark_test.cpp546
-rw-r--r--examples/Android.bp2
-rw-r--r--examples/ultrahdr_app.cpp6
-rw-r--r--fuzzer/ultrahdr_dec_fuzzer.cpp4
-rw-r--r--fuzzer/ultrahdr_enc_fuzzer.cpp4
-rw-r--r--lib/include/ultrahdr/jpegdecoderhelper.h14
-rw-r--r--lib/include/ultrahdr/jpegr.h36
-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
-rw-r--r--tests/jpegdecoderhelper_test.cpp34
-rw-r--r--tests/jpegr_test.cpp4
19 files changed, 857 insertions, 180 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 857972a..ae48d10 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -336,10 +336,14 @@ if(UHDR_BUILD_TESTS OR UHDR_BUILD_BENCHMARK)
if(WIN32)
file(COPY "${TESTS_DIR}/data/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/data")
else()
- execute_process(COMMAND cmake -E create_symlink
- "${TESTS_DIR}/data/"
- "${CMAKE_CURRENT_BINARY_DIR}/data"
- )
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink
+ "${TESTS_DIR}/data/" "${CMAKE_CURRENT_BINARY_DIR}/data"
+ RESULT_VARIABLE result
+ ERROR_VARIABLE errorinfo)
+ string(FIND "${errorinfo}" "error" errorstatus)
+ if(result GREATER 0 OR errorstatus GREATER -1)
+ message(FATAL_ERROR "Creating sym link failed with info ${errorinfo}")
+ endif()
endif()
endif()
@@ -368,6 +372,41 @@ if(UHDR_BUILD_BENCHMARK)
target_link_options(ultrahdr_bm PRIVATE -fsanitize=fuzzer-no-link)
endif()
target_link_libraries(ultrahdr_bm ultrahdr ${BENCHMARK_LIBRARIES})
+
+ set(RES_FILE "${TESTS_DIR}/data/UltrahdrBenchmarkTestRes-1.0.zip")
+ set(RES_FILE_MD5SUM "96651c5c07505c37aa017c57f480e6c1")
+ set(GET_RES_FILE TRUE)
+ if(EXISTS ${RES_FILE})
+ file(MD5 ${RES_FILE} CURR_MD5_SUM)
+ if(CURR_MD5_SUM STREQUAL RES_FILE_MD5SUM)
+ message("Zip File already exists: " ${RES_FILE})
+ set(GET_RES_FILE FALSE)
+ else()
+ file(REMOVE "${RES_FILE}")
+ endif()
+ endif()
+
+ if(GET_RES_FILE)
+ message("-- Downloading benchmark test resources")
+ set(RES_URL "https://storage.googleapis.com/android_media/external/libultrahdr/benchmark/UltrahdrBenchmarkTestRes-1.0.zip")
+ file(DOWNLOAD ${RES_URL} ${RES_FILE} STATUS result EXPECTED_MD5 ${RES_FILE_MD5SUM})
+ list(GET result 0 retval)
+ if(retval)
+ file(REMOVE "${RES_FILE}")
+ list(GET result 0 errcode)
+ list(GET result 1 info)
+ message(FATAL_ERROR "Error downloading ${RES_URL}: ${info} (${errcode})")
+ endif()
+ endif()
+ message("-- Extracting benchmark test resources")
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E tar xf "${RES_FILE}"
+ WORKING_DIRECTORY "${TESTS_DIR}/data/"
+ RESULT_VARIABLE result
+ ERROR_VARIABLE errorinfo)
+ string(FIND "${errorinfo}" "error" errorstatus)
+ if(result GREATER 0 OR errorstatus GREATER -1)
+ message(FATAL_ERROR "Extracting benchmark test resources failed with info ${errorinfo}")
+ endif()
endif()
if(UHDR_BUILD_FUZZERS)
diff --git a/METADATA b/METADATA
index 53ba696..891ab61 100644
--- a/METADATA
+++ b/METADATA
@@ -5,15 +5,15 @@
name: "libultrahdr"
description: "Android fork of the libultrahdr library."
third_party {
- url {
- type: GIT
- value: "https://github.com/google/libultrahdr.git"
- }
- version: "14849e395741d01326bd68deb785da912b88cbd1"
license_type: NOTICE
last_upgrade_date {
- year: 2023
- month: 11
- day: 29
+ year: 2024
+ month: 1
+ day: 9
+ }
+ identifier {
+ type: "Git"
+ value: "https://github.com/google/libultrahdr.git"
+ version: "3f9c0ec5590c2fa47b78a8bc125ca5e6b27e5728"
}
}
diff --git a/README.md b/README.md
index 5c341b3..10082d7 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,15 @@ This will generate the following files under *{build_directory}*:
NOTE: To not build unit tests, skip passing -DUHDR_BUILD_TESTS=1
+### Building Benchmark
+
+To build benchmarks, pass -DUHDR_BUILD_BENCHMARK=1 to cmake configure command and build.
+
+This will additionally generate,
+
+**ultrahdr_bm**<br> Benchmark tests
+
+
### Building Fuzzers
Refer to [README.md](fuzzer/README.md) for complete instructions.
@@ -132,5 +141,26 @@ Using libultrahdr
libultrahdr includes two classes of APIs, one to compress and the other to
decompress HDR images:
+List of encode APIs:
+| Input | HDR YUV | SDR YUV | JPEG | Encoded gainmap | Quality (0 ~ 100) | EXIF | Use case |
+| ------------- | ------------- | ------------- | ------------- | ------------- | ------------- | ------------- | ------------- |
+| API-0 | P010 | No | No | No | Required | Optional | Experimental only. |
+| API-1 | P010 | YUV_420 | No | No | Required | Optional | Raw SDR input. Primary image will be encoded from the raw SDR input in the library. |
+| API-2 | P010 | YUV_420 | Yes | No | No | No | Both JPEG and raw SDR inputs. Gainmap will be calculated from raw HDR and raw SDR inputs, the JPEG input will be preserved (including metadata) as the primary image. |
+| API-3 | P010 | No | Yes | No | No | No | SDR JPEG input. Gainmap will be calculated from raw HDR and the decoding result of the JPEG input, the JPEG input will be preserved (including metadata) as the primary image. |
+| API-4 | No | No | Yes | Yes | No | No | SDR JPEG and gainmap inputs. The library will only generate the Ultra HDR related metadata and write everything into the Ultra HDR format, all other metadata from the JPEG input will be preserved. |
+
+List of decode API:
+| Input | Usage |
+| ------------- | ------------- |
+| compressed_jpegr_image | The input data. Pointer to JPEG/R stream. |
+| dest | The output data. Destination that decoded data to be written. |
+| max_display_boost | (optional, >= 1.0) the maximum available boost supported by a display. |
+| exif | (optional, default to NULL) Destination that exif data to be written. |
+| recovery_map | (optional, default to NULL) Destination that decoded recovery map data to be written. |
+| output_format | <table><thead><tr><th>Value</th><th>Color format to be written</th></tr></thead><tbody><tr><td>SDR</td><td>RGBA_8888</td></tr><tr><td>HDR_LINEAR</td><td>(default) RGBA_F16 linear</td></tr><tr><td>HDR_PQ</td><td>RGBA_1010102 PQ</td></tr><tr><td>HDR_HLG</td><td>RGBA_1010102 HLG</td></tr></tbody></table> |
+| metadata | (optional, default to NULL) Destination of metadata (recovery map version, min/max content boost). |
+
+For more info:
- Refer to [jpegr.h](lib/include/ultrahdr/jpegr.h) for detailed description of various encode and decode api.
- Refer to [ultrahdr_app.cpp](examples/ultrahdr_app.cpp) for examples of its usage.
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index 1dc6ccf..6cd91a8 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2022 The Android Open Source Project
+// Copyright 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/benchmark/AndroidTest.xml b/benchmark/AndroidTest.xml
new file mode 100644
index 0000000..f002f65
--- /dev/null
+++ b/benchmark/AndroidTest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for ultrahdr benchmark tests">
+ <option name="test-suite-tag" value="ultrahdr_benchmark" />
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="ultrahdr_benchmark->/data/local/tmp/ultrahdr_benchmark/" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="host" />
+ <option name="config-filename" value="ultrahdr_benchmark" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
+ <option name="push-all" value="true" />
+ <option name="media-folder-name" value="UltrahdrBenchmarkTestRes-1.0"/>
+ <option name="dynamic-config-module" value="ultrahdr_benchmark" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" >
+ <option name="native-benchmark-device-path" value="/data/local/tmp" />
+ <option name="benchmark-module-name" value="ultrahdr_benchmark" />
+ <option name="file-exclusion-filter-regex" value=".*/bench_[^/]*$" />
+ </test>
+</configuration>
diff --git a/benchmark/DynamicConfig.xml b/benchmark/DynamicConfig.xml
new file mode 100644
index 0000000..9953ef2
--- /dev/null
+++ b/benchmark/DynamicConfig.xml
@@ -0,0 +1,20 @@
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<dynamicConfig>
+ <entry key="media_files_url">
+ <value>https://storage.googleapis.com/android_media/external/libultrahdr/benchmark/UltrahdrBenchmarkTestRes-1.0.zip</value>
+ </entry>
+</dynamicConfig> \ No newline at end of file
diff --git a/benchmark/benchmark_test.cpp b/benchmark/benchmark_test.cpp
index d013838..4148802 100644
--- a/benchmark/benchmark_test.cpp
+++ b/benchmark/benchmark_test.cpp
@@ -19,17 +19,88 @@
#include <benchmark/benchmark.h>
-#include "ultrahdr/jpegr.h"
+#include "ultrahdr/jpegrutils.h"
using namespace ultrahdr;
-const std::string kDecTestVectors[] = {
- "./data/city_night.jpg", "./data/desert_sunset.jpg", "./data/lamps.jpg",
- "./data/mountains.jpg", "./data/desert_wanda.jpg", "./data/grand_canyon.jpg",
- "./data/mountain_lake.jpg",
+#ifdef __ANDROID__
+std::string kTestImagesPath = "/sdcard/test/UltrahdrBenchmarkTestRes-1.0/";
+#else
+std::string kTestImagesPath = "./data/UltrahdrBenchmarkTestRes-1.0/";
+#endif
+
+std::vector<std::string> kDecodeAPITestImages{
+ // 12mp test vectors
+ "mountains.jpg",
+ "mountain_lake.jpg",
+ "desert_wanda.jpg",
+ // 3mp test vectors
+ "mountains_3mp.jpg",
+ "mountain_lake_3mp.jpg",
+ "desert_wanda_3mp.jpg",
+};
+
+std::vector<std::string> kEncodeApi0TestImages12MpName{
+ // 12mp test vectors
+ "mountains.p010",
+ "mountain_lake.p010",
+};
+
+std::vector<std::string> kEncodeApi0TestImages3MpName{
+ // 3mp test vectors
+ "mountains_3mp.p010",
+ "mountain_lake_3mp.p010",
+};
+
+std::vector<std::pair<std::string, std::string>> kEncodeApi1TestImages12MpName{
+ // 12mp test vectors
+ {"mountains.p010", "mountains.yuv"},
+ {"mountain_lake.p010", "mountain_lake.yuv"},
+};
+
+std::vector<std::pair<std::string, std::string>> kEncodeApi1TestImages3MpName{
+ // 3mp test vectors
+ {"mountains_3mp.p010", "mountains_3mp.yuv"},
+ {"mountain_lake_3mp.p010", "mountain_lake_3mp.yuv"},
+};
+
+std::vector<std::tuple<std::string, std::string, std::string>> kEncodeApi2TestImages12MpName{
+ // 12mp test vectors
+ {"mountains.p010", "mountains.yuv", "mountains.jpg"},
+ {"mountain_lake.p010", "mountain_lake.yuv", "mountain_lake.jpg"},
};
-const size_t kNumDecTestVectors = std::size(kDecTestVectors);
+std::vector<std::tuple<std::string, std::string, std::string>> kEncodeApi2TestImages3MpName{
+ // 3mp test vectors
+ {"mountains_3mp.p010", "mountains_3mp.yuv", "mountains_3mp.jpg"},
+ {"mountain_lake_3mp.p010", "mountain_lake_3mp.yuv", "mountain_lake_3mp.jpg"},
+};
+
+std::vector<std::pair<std::string, std::string>> kEncodeApi3TestImages12MpName{
+ // 12mp test vectors
+ {"mountains.p010", "mountains.jpg"},
+ {"mountain_lake.p010", "mountain_lake.jpg"},
+};
+
+std::vector<std::pair<std::string, std::string>> kEncodeApi3TestImages3MpName{
+ // 3mp test vectors
+ {"mountains_3mp.p010", "mountains_3mp.jpg"},
+ {"mountain_lake_3mp.p010", "mountain_lake_3mp.jpg"},
+};
+
+std::vector<std::string> kEncodeApi4TestImages12MpName{
+ // 12mp test vectors
+ "mountains.jpg",
+ "mountain_lake.jpg",
+ "desert_wanda.jpg",
+};
+
+std::vector<std::string> kEncodeApi4TestImages3MpName{
+ // 3mp test vectors
+ "mountains_3mp.jpg",
+ "mountain_lake_3mp.jpg",
+ "desert_wanda_3mp.jpg",
+};
std::string ofToString(const ultrahdr_output_format of) {
switch (of) {
@@ -46,6 +117,34 @@ std::string ofToString(const ultrahdr_output_format of) {
}
}
+std::string colorGamutToString(const ultrahdr_color_gamut cg) {
+ switch (cg) {
+ case ULTRAHDR_COLORGAMUT_BT709:
+ return "bt709";
+ case ULTRAHDR_COLORGAMUT_P3:
+ return "p3";
+ case ULTRAHDR_COLORGAMUT_BT2100:
+ return "bt2100";
+ default:
+ return "Unknown";
+ }
+}
+
+std::string tfToString(const ultrahdr_transfer_function of) {
+ switch (of) {
+ case ULTRAHDR_TF_LINEAR:
+ return "linear";
+ case ULTRAHDR_TF_HLG:
+ return "hlg";
+ case ULTRAHDR_TF_PQ:
+ return "pq";
+ case ULTRAHDR_TF_SRGB:
+ return "srgb";
+ default:
+ return "Unknown";
+ }
+}
+
static bool loadFile(const char* filename, void*& result, int length) {
std::ifstream ifd(filename, std::ios::binary | std::ios::ate);
if (ifd.good()) {
@@ -69,8 +168,33 @@ static bool loadFile(const char* filename, void*& result, int length) {
return false;
}
+bool fillRawImageHandle(jpegr_uncompressed_struct* rawImage, int width, int height,
+ std::string file, ultrahdr_color_gamut cg, bool isP010) {
+ const int bpp = isP010 ? 2 : 1;
+ int imgSize = width * height * bpp * 1.5;
+ rawImage->width = width;
+ rawImage->height = height;
+ rawImage->colorGamut = cg;
+ return loadFile(file.c_str(), rawImage->data, imgSize);
+}
+
+bool fillJpgImageHandle(jpegr_compressed_struct* jpgImg, std::string file,
+ ultrahdr_color_gamut colorGamut) {
+ std::ifstream ifd(file.c_str(), std::ios::binary | std::ios::ate);
+ if (!ifd.good()) {
+ return false;
+ }
+ int size = ifd.tellg();
+ jpgImg->length = size;
+ jpgImg->maxLength = size;
+ jpgImg->data = nullptr;
+ jpgImg->colorGamut = colorGamut;
+ ifd.close();
+ return loadFile(file.c_str(), jpgImg->data, size);
+}
+
static void BM_Decode(benchmark::State& s) {
- std::string srcFileName = kDecTestVectors[s.range(0)];
+ std::string srcFileName = kTestImagesPath + "jpegr/" + kDecodeAPITestImages[s.range(0)];
ultrahdr_output_format of = static_cast<ultrahdr_output_format>(s.range(1));
std::ifstream ifd(srcFileName.c_str(), std::ios::binary | std::ios::ate);
@@ -95,11 +219,10 @@ static void BM_Decode(benchmark::State& s) {
compData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
JpegR jpegHdr;
- std::vector<uint8_t> iccData(0);
- std::vector<uint8_t> exifData(0);
- jpegr_info_struct info{0, 0, &iccData, &exifData};
- if (JPEGR_NO_ERROR != jpegHdr.getJPEGRInfo(&jpegImgR, &info)) {
- s.SkipWithError("getJPEGRInfo returned with error ");
+ jpegr_info_struct info{};
+ status_t status = jpegHdr.getJPEGRInfo(&jpegImgR, &info);
+ if (JPEGR_NO_ERROR != status) {
+ s.SkipWithError("getJPEGRInfo returned with error " + std::to_string(status));
return;
}
@@ -108,8 +231,9 @@ static void BM_Decode(benchmark::State& s) {
jpegr_uncompressed_struct destImage{};
destImage.data = data.get();
for (auto _ : s) {
- if (JPEGR_NO_ERROR != jpegHdr.decodeJPEGR(&jpegImgR, &destImage, FLT_MAX, nullptr, of)) {
- s.SkipWithError("decodeJPEGR returned with error ");
+ status = jpegHdr.decodeJPEGR(&jpegImgR, &destImage, FLT_MAX, nullptr, of);
+ if (JPEGR_NO_ERROR != status) {
+ s.SkipWithError("decodeJPEGR returned with error " + std::to_string(status));
return;
}
}
@@ -118,14 +242,398 @@ static void BM_Decode(benchmark::State& s) {
return;
}
- s.SetLabel(srcFileName + ", " + ofToString(of) + ", " + std::to_string(info.width) + "x" +
- std::to_string(info.height));
+ s.SetLabel(srcFileName + ", OutputFormat: " + ofToString(of) + ", " + std::to_string(info.width) +
+ "x" + std::to_string(info.height));
+}
+
+static void BM_Encode_Api0(benchmark::State& s, std::vector<std::string> testVectors) {
+ int width = s.range(1);
+ int height = s.range(2);
+ ultrahdr_color_gamut p010Cg = static_cast<ultrahdr_color_gamut>(s.range(3));
+ ultrahdr_transfer_function tf = static_cast<ultrahdr_transfer_function>(s.range(4));
+
+ s.SetLabel(testVectors[s.range(0)] + ", " + colorGamutToString(p010Cg) + ", " + tfToString(tf) +
+ ", " + std::to_string(width) + "x" + std::to_string(height));
+
+ std::string p010File{kTestImagesPath + "p010/" + testVectors[s.range(0)]};
+
+ jpegr_uncompressed_struct rawP010Image{};
+ if (!fillRawImageHandle(&rawP010Image, width, height, p010File, p010Cg, true)) {
+ s.SkipWithError("unable to load file : " + p010File);
+ return;
+ }
+ std::unique_ptr<uint8_t[]> rawP010ImgData;
+ rawP010ImgData.reset(reinterpret_cast<uint8_t*>(rawP010Image.data));
+
+ jpegr_compressed_struct jpegImgR{};
+ jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
+ rawP010Image.width * rawP010Image.height * 3 * 2);
+ jpegImgR.data = new uint8_t[jpegImgR.maxLength];
+ if (jpegImgR.data == nullptr) {
+ s.SkipWithError("unable to allocate memory to store compressed image");
+ return;
+ }
+ std::unique_ptr<uint8_t[]> jpegImgRData;
+ jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
+
+ JpegR jpegHdr;
+ for (auto _ : s) {
+ status_t status = jpegHdr.encodeJPEGR(&rawP010Image, tf, &jpegImgR, 95, nullptr);
+ if (JPEGR_NO_ERROR != status) {
+ s.SkipWithError("encodeJPEGR returned with error : " + std::to_string(status));
+ return;
+ }
+ }
+}
+
+static void BM_Encode_Api1(benchmark::State& s,
+ std::vector<std::pair<std::string, std::string>> testVectors) {
+ int width = s.range(1);
+ int height = s.range(2);
+ ultrahdr_color_gamut p010Cg = static_cast<ultrahdr_color_gamut>(s.range(3));
+ ultrahdr_color_gamut yuv420Cg = static_cast<ultrahdr_color_gamut>(s.range(4));
+ ultrahdr_transfer_function tf = static_cast<ultrahdr_transfer_function>(s.range(5));
+
+ s.SetLabel(testVectors[s.range(0)].first + ", " + testVectors[s.range(0)].second + ", " +
+ "p010_" + colorGamutToString(p010Cg) + ", " + "yuv420_" +
+ colorGamutToString(yuv420Cg) + ", " + tfToString(tf) + ", " + std::to_string(width) +
+ "x" + std::to_string(height));
+
+ std::string p010File{kTestImagesPath + "p010/" + testVectors[s.range(0)].first};
+
+ jpegr_uncompressed_struct rawP010Image{};
+ if (!fillRawImageHandle(&rawP010Image, width, height, p010File, p010Cg, true)) {
+ s.SkipWithError("unable to load file : " + p010File);
+ return;
+ }
+ std::unique_ptr<uint8_t[]> rawP010ImgData;
+ rawP010ImgData.reset(reinterpret_cast<uint8_t*>(rawP010Image.data));
+
+ std::string yuv420File{kTestImagesPath + "yuv420/" + testVectors[s.range(0)].second};
+
+ jpegr_uncompressed_struct rawYuv420Image{};
+ if (!fillRawImageHandle(&rawYuv420Image, width, height, yuv420File, yuv420Cg, false)) {
+ s.SkipWithError("unable to load file : " + yuv420File);
+ return;
+ }
+ std::unique_ptr<uint8_t[]> rawYuv420ImgData;
+ rawYuv420ImgData.reset(reinterpret_cast<uint8_t*>(rawYuv420Image.data));
+
+ jpegr_compressed_struct jpegImgR{};
+ jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
+ rawP010Image.width * rawP010Image.height * 3 * 2);
+ jpegImgR.data = new uint8_t[jpegImgR.maxLength];
+
+ std::unique_ptr<uint8_t[]> jpegImgRData;
+ jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
+
+ JpegR jpegHdr;
+ for (auto _ : s) {
+ status_t status =
+ jpegHdr.encodeJPEGR(&rawP010Image, &rawYuv420Image, tf, &jpegImgR, 95, nullptr);
+ if (JPEGR_NO_ERROR != status) {
+ s.SkipWithError("encodeJPEGR returned with error : " + std::to_string(status));
+ return;
+ }
+ }
+}
+
+static void BM_Encode_Api2(
+ benchmark::State& s,
+ std::vector<std::tuple<std::string, std::string, std::string>> testVectors) {
+ int width = s.range(1);
+ int height = s.range(2);
+ ultrahdr_color_gamut p010Cg = static_cast<ultrahdr_color_gamut>(s.range(3));
+ ultrahdr_transfer_function tf = static_cast<ultrahdr_transfer_function>(s.range(4));
+
+ s.SetLabel(std::get<0>(testVectors[s.range(0)]) + ", " + std::get<1>(testVectors[s.range(0)]) +
+ ", " + std::get<2>(testVectors[s.range(0)]) + ", " + colorGamutToString(p010Cg) +
+ ", " + tfToString(tf) + ", " + std::to_string(width) + "x" + std::to_string(height));
+
+ std::string p010File{kTestImagesPath + "p010/" + std::get<0>(testVectors[s.range(0)])};
+
+ jpegr_uncompressed_struct rawP010Image{};
+ if (!fillRawImageHandle(&rawP010Image, width, height, p010File, p010Cg, true)) {
+ s.SkipWithError("unable to load file : " + p010File);
+ return;
+ }
+ std::unique_ptr<uint8_t[]> rawP010ImgData;
+ rawP010ImgData.reset(reinterpret_cast<uint8_t*>(rawP010Image.data));
+
+ std::string yuv420File{kTestImagesPath + "yuv420/" + std::get<1>(testVectors[s.range(0)])};
+
+ jpegr_uncompressed_struct rawYuv420Image{};
+ if (!fillRawImageHandle(&rawYuv420Image, width, height, yuv420File, ULTRAHDR_COLORGAMUT_P3,
+ false)) {
+ s.SkipWithError("unable to load file : " + yuv420File);
+ return;
+ }
+ std::unique_ptr<uint8_t[]> rawYuv420ImgData;
+ rawYuv420ImgData.reset(reinterpret_cast<uint8_t*>(rawYuv420Image.data));
+
+ std::string yuv420JpegFile{
+ (kTestImagesPath + "yuv420jpeg/" + std::get<2>(testVectors[s.range(0)]))};
+
+ jpegr_compressed_struct yuv420JpegImage{};
+ if (!fillJpgImageHandle(&yuv420JpegImage, yuv420JpegFile, ULTRAHDR_COLORGAMUT_P3)) {
+ s.SkipWithError("unable to load file : " + yuv420JpegFile);
+ return;
+ }
+ std::unique_ptr<uint8_t[]> yuv420jpegImgData;
+ yuv420jpegImgData.reset(reinterpret_cast<uint8_t*>(yuv420JpegImage.data));
+
+ jpegr_compressed_struct jpegImgR{};
+ jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
+ rawP010Image.width * rawP010Image.height * 3 * 2);
+ jpegImgR.data = new uint8_t[jpegImgR.maxLength];
+ if (jpegImgR.data == nullptr) {
+ s.SkipWithError("unable to allocate memory to store compressed image");
+ return;
+ }
+ std::unique_ptr<uint8_t[]> jpegImgRData;
+ jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
+
+ JpegR jpegHdr;
+ for (auto _ : s) {
+ status_t status =
+ jpegHdr.encodeJPEGR(&rawP010Image, &rawYuv420Image, &yuv420JpegImage, tf, &jpegImgR);
+ if (JPEGR_NO_ERROR != status) {
+ s.SkipWithError("encodeJPEGR returned with error : " + std::to_string(status));
+ return;
+ }
+ }
+}
+
+static void BM_Encode_Api3(benchmark::State& s,
+ std::vector<std::pair<std::string, std::string>> testVectors) {
+ int width = s.range(1);
+ int height = s.range(2);
+ ultrahdr_color_gamut p010Cg = static_cast<ultrahdr_color_gamut>(s.range(3));
+ ultrahdr_transfer_function tf = static_cast<ultrahdr_transfer_function>(s.range(4));
+
+ s.SetLabel(testVectors[s.range(0)].first + ", " + testVectors[s.range(0)].second + ", " +
+ colorGamutToString(p010Cg) + ", " + tfToString(tf) + ", " + std::to_string(width) +
+ "x" + std::to_string(height));
+
+ std::string p010File{kTestImagesPath + "p010/" + testVectors[s.range(0)].first};
+
+ jpegr_uncompressed_struct rawP010Image{};
+ if (!fillRawImageHandle(&rawP010Image, width, height, p010File, p010Cg, true)) {
+ s.SkipWithError("unable to load file : " + p010File);
+ return;
+ }
+ std::unique_ptr<uint8_t[]> rawP010ImgData;
+ rawP010ImgData.reset(reinterpret_cast<uint8_t*>(rawP010Image.data));
+
+ std::string yuv420JpegFile{(kTestImagesPath + "yuv420jpeg/" + testVectors[s.range(0)].second)};
+
+ jpegr_compressed_struct yuv420JpegImage{};
+ if (!fillJpgImageHandle(&yuv420JpegImage, yuv420JpegFile, ULTRAHDR_COLORGAMUT_P3)) {
+ s.SkipWithError("unable to load file : " + yuv420JpegFile);
+ return;
+ }
+ std::unique_ptr<uint8_t[]> yuv420jpegImgData;
+ yuv420jpegImgData.reset(reinterpret_cast<uint8_t*>(yuv420JpegImage.data));
+
+ jpegr_compressed_struct jpegImgR{};
+ jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
+ rawP010Image.width * rawP010Image.height * 3 * 2);
+ jpegImgR.data = new uint8_t[jpegImgR.maxLength];
+ if (jpegImgR.data == nullptr) {
+ s.SkipWithError("unable to allocate memory to store compressed image");
+ return;
+ }
+ std::unique_ptr<uint8_t[]> jpegImgRData;
+ jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
+
+ JpegR jpegHdr;
+ for (auto _ : s) {
+ status_t status = jpegHdr.encodeJPEGR(&rawP010Image, &yuv420JpegImage, tf, &jpegImgR);
+ if (JPEGR_NO_ERROR != status) {
+ s.SkipWithError("encodeJPEGR returned with error : " + std::to_string(status));
+ return;
+ }
+ }
+}
+
+static void BM_Encode_Api4(benchmark::State& s) {
+ std::string srcFileName = kTestImagesPath + "jpegr/" + kDecodeAPITestImages[s.range(0)];
+
+ std::ifstream ifd(srcFileName.c_str(), std::ios::binary | std::ios::ate);
+ if (!ifd.good()) {
+ s.SkipWithError("unable to open file " + srcFileName);
+ return;
+ }
+ int size = ifd.tellg();
+
+ jpegr_compressed_struct inpJpegImgR{};
+ inpJpegImgR.length = size;
+ inpJpegImgR.maxLength = size;
+ inpJpegImgR.data = nullptr;
+ inpJpegImgR.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;
+ ifd.close();
+ if (!loadFile(srcFileName.c_str(), inpJpegImgR.data, size)) {
+ s.SkipWithError("unable to load file " + srcFileName);
+ return;
+ }
+ std::unique_ptr<uint8_t[]> inpJpegImgRData;
+ inpJpegImgRData.reset(reinterpret_cast<uint8_t*>(inpJpegImgR.data));
+
+ JpegR jpegHdr;
+ jpeg_info_struct primaryImgInfo;
+ jpeg_info_struct gainmapImgInfo;
+ jpegr_info_struct info{};
+ info.primaryImgInfo = &primaryImgInfo;
+ info.gainmapImgInfo = &gainmapImgInfo;
+ status_t status = jpegHdr.getJPEGRInfo(&inpJpegImgR, &info);
+ if (JPEGR_NO_ERROR != status) {
+ s.SkipWithError("getJPEGRInfo returned with error " + std::to_string(status));
+ return;
+ }
+
+ jpegr_compressed_struct jpegImgR{};
+ jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
+ info.width * info.height * 3 * 2);
+ jpegImgR.data = new uint8_t[jpegImgR.maxLength];
+ if (jpegImgR.data == nullptr) {
+ s.SkipWithError("unable to allocate memory to store compressed image");
+ return;
+ }
+ std::unique_ptr<uint8_t[]> jpegImgRData;
+ jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
+
+ jpegr_compressed_struct primaryImg;
+ primaryImg.data = primaryImgInfo.imgData.data();
+ primaryImg.maxLength = primaryImg.length = primaryImgInfo.imgData.size();
+ primaryImg.colorGamut = static_cast<ultrahdr_color_gamut>(s.range(1));
+ jpegr_compressed_struct gainmapImg;
+ gainmapImg.data = gainmapImgInfo.imgData.data();
+ gainmapImg.maxLength = gainmapImg.length = gainmapImgInfo.imgData.size();
+ gainmapImg.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;
+ ultrahdr_metadata_struct uhdr_metadata;
+ if (!getMetadataFromXMP(gainmapImgInfo.xmpData.data(), gainmapImgInfo.xmpData.size(),
+ &uhdr_metadata)) {
+ s.SkipWithError("getMetadataFromXMP returned with error");
+ return;
+ }
+ for (auto _ : s) {
+ status = jpegHdr.encodeJPEGR(&primaryImg, &gainmapImg, &uhdr_metadata, &jpegImgR);
+ if (JPEGR_NO_ERROR != status) {
+ s.SkipWithError("encodeJPEGR returned with error " + std::to_string(status));
+ return;
+ }
+ }
+
+ s.SetLabel(srcFileName + ", " + std::to_string(info.width) + "x" + std::to_string(info.height));
}
BENCHMARK(BM_Decode)
- ->ArgsProduct({{benchmark::CreateDenseRange(0, kNumDecTestVectors - 1, 1)},
- {ULTRAHDR_OUTPUT_HDR_HLG, ULTRAHDR_OUTPUT_HDR_PQ, ULTRAHDR_OUTPUT_HDR_LINEAR,
- ULTRAHDR_OUTPUT_SDR}})
+ ->ArgsProduct({{benchmark::CreateDenseRange(0, kDecodeAPITestImages.size() - 1, 1)},
+ {ULTRAHDR_OUTPUT_HDR_HLG, ULTRAHDR_OUTPUT_HDR_PQ, ULTRAHDR_OUTPUT_SDR}})
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK_CAPTURE(BM_Encode_Api0, TestVectorName, kEncodeApi0TestImages12MpName)
+ ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi0TestImages12MpName.size() - 1, 1)},
+ {4080},
+ {3072},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {
+ ULTRAHDR_TF_HLG,
+ ULTRAHDR_TF_PQ,
+ }})
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK_CAPTURE(BM_Encode_Api0, TestVectorName, kEncodeApi0TestImages3MpName)
+ ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi0TestImages3MpName.size() - 1, 1)},
+ {2048},
+ {1536},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {
+ ULTRAHDR_TF_HLG,
+ ULTRAHDR_TF_PQ,
+ }})
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK_CAPTURE(BM_Encode_Api1, TestVectorName, kEncodeApi1TestImages12MpName)
+ ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi1TestImages12MpName.size() - 1, 1)},
+ {4080},
+ {3072},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {
+ ULTRAHDR_TF_HLG,
+ ULTRAHDR_TF_PQ,
+ }})
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK_CAPTURE(BM_Encode_Api1, TestVectorName, kEncodeApi1TestImages3MpName)
+ ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi1TestImages3MpName.size() - 1, 1)},
+ {2048},
+ {1536},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {
+ ULTRAHDR_TF_HLG,
+ ULTRAHDR_TF_PQ,
+ }})
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK_CAPTURE(BM_Encode_Api2, TestVectorName, kEncodeApi2TestImages12MpName)
+ ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi2TestImages12MpName.size() - 1, 1)},
+ {4080},
+ {3072},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {
+ ULTRAHDR_TF_HLG,
+ ULTRAHDR_TF_PQ,
+ }})
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK_CAPTURE(BM_Encode_Api2, TestVectorName, kEncodeApi2TestImages3MpName)
+ ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi2TestImages3MpName.size() - 1, 1)},
+ {2048},
+ {1536},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {
+ ULTRAHDR_TF_HLG,
+ ULTRAHDR_TF_PQ,
+ }})
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK_CAPTURE(BM_Encode_Api3, TestVectorName, kEncodeApi3TestImages12MpName)
+ ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi3TestImages12MpName.size() - 1, 1)},
+ {4080},
+ {3072},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {
+ ULTRAHDR_TF_HLG,
+ ULTRAHDR_TF_PQ,
+ }})
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK_CAPTURE(BM_Encode_Api3, TestVectorName, kEncodeApi3TestImages3MpName)
+ ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi3TestImages3MpName.size() - 1, 1)},
+ {2048},
+ {1536},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ {
+ ULTRAHDR_TF_HLG,
+ ULTRAHDR_TF_PQ,
+ }})
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK(BM_Encode_Api4)
+ ->ArgsProduct({
+ {benchmark::CreateDenseRange(0, kEncodeApi4TestImages12MpName.size() - 1, 1)},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ })
+ ->Unit(benchmark::kMillisecond);
+
+BENCHMARK(BM_Encode_Api4)
+ ->ArgsProduct({
+ {benchmark::CreateDenseRange(0, kEncodeApi4TestImages3MpName.size() - 1, 1)},
+ {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
+ })
->Unit(benchmark::kMillisecond);
BENCHMARK_MAIN();
diff --git a/examples/Android.bp b/examples/Android.bp
index 0ede18b..72b0777 100644
--- a/examples/Android.bp
+++ b/examples/Android.bp
@@ -22,7 +22,7 @@ package {
}
cc_binary {
- name: "ultrahdr_sample_app",
+ name: "ultrahdr_app",
host_supported: true,
srcs: [
"ultrahdr_app.cpp",
diff --git a/examples/ultrahdr_app.cpp b/examples/ultrahdr_app.cpp
index 43b4b50..20b9329 100644
--- a/examples/ultrahdr_app.cpp
+++ b/examples/ultrahdr_app.cpp
@@ -367,7 +367,7 @@ bool UltraHdrAppInput::decode() {
if (mMode == 1 && !fillJpegRImageHandle()) return false;
std::vector<uint8_t> iccData(0);
std::vector<uint8_t> exifData(0);
- jpegr_info_struct info{0, 0, &iccData, &exifData};
+ jpegr_info_struct info{};
JpegR jpegHdr;
status_t status = jpegHdr.getJPEGRInfo(&mJpegImgR, &info);
if (JPEGR_NO_ERROR == status) {
@@ -839,7 +839,7 @@ void UltraHdrAppInput::computeYUVSdrPSNR() {
static void usage(const char* name) {
fprintf(stderr, "\n## ultra hdr demo application.\nUsage : %s \n", name);
- fprintf(stderr, " -m mode of operation. [0: encode, 1:decode] \n");
+ fprintf(stderr, " -m mode of operation. [0:encode, 1:decode] \n");
fprintf(stderr, "\n## encoder options : \n");
fprintf(stderr, " -p raw 10 bit input resource in p010 color format, mandatory. \n");
fprintf(stderr,
@@ -855,7 +855,7 @@ static void usage(const char* name) {
" -q quality factor to be used while encoding 8 bit image, optional. [0-100].\n"
" gain map image does not use this quality factor. \n"
" for now gain map image quality factor is not configurable. \n");
- fprintf(stderr, " -e compute psnr, optional. [0:yes, 1:no] \n");
+ fprintf(stderr, " -e compute psnr, optional. [0:no, 1:yes] \n");
fprintf(stderr, "\n## decoder options : \n");
fprintf(stderr, " -j ultra hdr input resource, mandatory in decode mode. \n");
fprintf(stderr,
diff --git a/fuzzer/ultrahdr_dec_fuzzer.cpp b/fuzzer/ultrahdr_dec_fuzzer.cpp
index 49dc913..4adc942 100644
--- a/fuzzer/ultrahdr_dec_fuzzer.cpp
+++ b/fuzzer/ultrahdr_dec_fuzzer.cpp
@@ -42,9 +42,7 @@ void UltraHdrDecFuzzer::process() {
jpegr_compressed_struct jpegImgR{buffer.data(), (int)buffer.size(), (int)buffer.size(),
ULTRAHDR_COLORGAMUT_UNSPECIFIED};
- std::vector<uint8_t> iccData(0);
- std::vector<uint8_t> exifData(0);
- jpegr_info_struct info{0, 0, &iccData, &exifData};
+ jpegr_info_struct info{};
JpegR jpegHdr;
(void)jpegHdr.getJPEGRInfo(&jpegImgR, &info);
//#define DUMP_PARAM
diff --git a/fuzzer/ultrahdr_enc_fuzzer.cpp b/fuzzer/ultrahdr_enc_fuzzer.cpp
index 23cc845..ff749c7 100644
--- a/fuzzer/ultrahdr_enc_fuzzer.cpp
+++ b/fuzzer/ultrahdr_enc_fuzzer.cpp
@@ -289,9 +289,7 @@ void UltraHdrEncFuzzer::process() {
}
}
if (status == JPEGR_NO_ERROR) {
- std::vector<uint8_t> iccData(0);
- std::vector<uint8_t> exifData(0);
- jpegr_info_struct info{0, 0, &iccData, &exifData};
+ jpegr_info_struct info{};
status = jpegHdr.getJPEGRInfo(&jpegImgR, &info);
if (status == JPEGR_NO_ERROR) {
size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4);
diff --git a/lib/include/ultrahdr/jpegdecoderhelper.h b/lib/include/ultrahdr/jpegdecoderhelper.h
index 01a05e4..d0b1f6f 100644
--- a/lib/include/ultrahdr/jpegdecoderhelper.h
+++ b/lib/include/ultrahdr/jpegdecoderhelper.h
@@ -41,6 +41,13 @@ static const int kMaxWidth = 8192;
static const int kMaxHeight = 8192;
namespace ultrahdr {
+
+typedef enum {
+ PARSE_ONLY = 0, // Dont decode. Parse for dimensions, EXIF, ICC, XMP
+ DECODE_TO_RGBA = 1, // Parse and decode to rgba
+ DECODE_TO_YCBCR = 2, // Parse and decode to YCBCR or Grayscale
+} decode_mode_t;
+
/*
* Encapsulates a converter from JPEG to raw image (YUV420planer or grey-scale) format.
* This class is not thread-safe.
@@ -54,7 +61,7 @@ class JpegDecoderHelper {
* calling this method, call getDecompressedImage() to get the image.
* Returns false if decompressing the image fails.
*/
- bool decompressImage(const void* image, int length, bool decodeToRGBA = false);
+ bool decompressImage(const void* image, int length, decode_mode_t decodeTo = DECODE_TO_YCBCR);
/*
* Returns the decompressed raw image buffer pointer. This method must be called only after
* calling decompressImage().
@@ -117,11 +124,10 @@ class JpegDecoderHelper {
/*
* Decompresses metadata of the image. All vectors are owned by the caller.
*/
- bool getCompressedImageParameters(const void* image, int length, size_t* pWidth, size_t* pHeight,
- std::vector<uint8_t>* iccData, std::vector<uint8_t>* exifData);
+ bool getCompressedImageParameters(const void* image, int length);
private:
- bool decode(const void* image, int length, bool decodeToRGBA);
+ bool decode(const void* image, int length, decode_mode_t decodeTo);
// Returns false if errors occur.
bool decompress(jpeg_decompress_struct* cinfo, const uint8_t* dest, bool isSingleChannel);
bool decompressYUV(jpeg_decompress_struct* cinfo, const uint8_t* dest);
diff --git a/lib/include/ultrahdr/jpegr.h b/lib/include/ultrahdr/jpegr.h
index 8ac227d..49ddaea 100644
--- a/lib/include/ultrahdr/jpegr.h
+++ b/lib/include/ultrahdr/jpegr.h
@@ -61,18 +61,31 @@ typedef enum {
ERROR_JPEGR_METADATA_ERROR = JPEGR_RUNTIME_ERROR_BASE - 5,
ERROR_JPEGR_NO_IMAGES_FOUND = JPEGR_RUNTIME_ERROR_BASE - 6,
ERROR_JPEGR_MULTIPLE_EXIFS_RECEIVED = JPEGR_RUNTIME_ERROR_BASE - 7,
+ ERROR_JPEGR_UNSUPPORTED_MAP_SCALE_FACTOR = JPEGR_RUNTIME_ERROR_BASE - 8,
ERROR_JPEGR_UNSUPPORTED_FEATURE = -30000,
} status_t;
/*
- * Holds information of jpegr image
+ * Holds information of jpeg image
*/
-struct jpegr_info_struct {
+struct jpeg_info_struct {
+ std::vector<uint8_t> imgData = std::vector<uint8_t>(0);
+ std::vector<uint8_t> iccData = std::vector<uint8_t>(0);
+ std::vector<uint8_t> exifData = std::vector<uint8_t>(0);
+ std::vector<uint8_t> xmpData = std::vector<uint8_t>(0);
size_t width;
size_t height;
- std::vector<uint8_t>* iccData;
- std::vector<uint8_t>* exifData;
+};
+
+/*
+ * Holds information of jpegr image
+ */
+struct jpegr_info_struct {
+ size_t width; // copy of primary image width (for easier access)
+ size_t height; // copy of primary image height (for easier access)
+ jpeg_info_struct* primaryImgInfo = nullptr;
+ jpeg_info_struct* gainmapImgInfo = nullptr;
};
/*
@@ -133,6 +146,7 @@ struct jpegr_exif_struct {
typedef struct jpegr_uncompressed_struct* jr_uncompressed_ptr;
typedef struct jpegr_compressed_struct* jr_compressed_ptr;
typedef struct jpegr_exif_struct* jr_exif_ptr;
+typedef struct jpeg_info_struct* j_info_ptr;
typedef struct jpegr_info_struct* jr_info_ptr;
class JpegR {
@@ -374,6 +388,20 @@ class JpegR {
jr_compressed_ptr gainmap_jpg_image_ptr);
/*
+ * Gets Info from JPEG image without decoding it.
+ *
+ * The output is filled jpeg_info structure
+ * @param jpegr_image_ptr compressed JPEG image
+ * @param jpeg_image_info_ptr pointer to jpeg info struct. Members of jpeg_info_struct
+ * are owned by the caller
+ * @param img_width (optional) pointer to store width of jpeg image
+ * @param img_height (optional) pointer to store height of jpeg image
+ * @return NO_ERROR if JPEGR parsing succeeds, error code otherwise
+ */
+ status_t parseJpegInfo(jr_compressed_ptr jpeg_image_ptr, j_info_ptr jpeg_image_info_ptr,
+ size_t* img_width = nullptr, size_t* img_height = nullptr);
+
+ /*
* This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image,
* the compressed gain map and optionally the exif package as inputs, and generate the XMP
* metadata, and finally append everything in the order of:
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--;
}
diff --git a/tests/jpegdecoderhelper_test.cpp b/tests/jpegdecoderhelper_test.cpp
index 4e72be1..ef6df1d 100644
--- a/tests/jpegdecoderhelper_test.cpp
+++ b/tests/jpegdecoderhelper_test.cpp
@@ -115,33 +115,23 @@ TEST_F(JpegDecoderHelperTest, decodeGreyImage) {
}
TEST_F(JpegDecoderHelperTest, getCompressedImageParameters) {
- size_t width = 0, height = 0;
- std::vector<uint8_t> icc, exif;
-
JpegDecoderHelper decoder;
- EXPECT_TRUE(decoder.getCompressedImageParameters(mYuvImage.buffer.get(), mYuvImage.size, &width,
- &height, &icc, &exif));
-
- EXPECT_EQ(width, IMAGE_WIDTH);
- EXPECT_EQ(height, IMAGE_HEIGHT);
- EXPECT_EQ(icc.size(), 0);
- EXPECT_EQ(exif.size(), 0);
+ EXPECT_TRUE(decoder.getCompressedImageParameters(mYuvImage.buffer.get(), mYuvImage.size));
+ EXPECT_EQ(IMAGE_WIDTH, decoder.getDecompressedImageWidth());
+ EXPECT_EQ(IMAGE_HEIGHT, decoder.getDecompressedImageHeight());
+ EXPECT_EQ(decoder.getICCSize(), 0);
+ EXPECT_EQ(decoder.getEXIFSize(), 0);
}
TEST_F(JpegDecoderHelperTest, getCompressedImageParametersIcc) {
- size_t width = 0, height = 0;
- std::vector<uint8_t> icc, exif;
-
JpegDecoderHelper decoder;
- EXPECT_TRUE(decoder.getCompressedImageParameters(mYuvIccImage.buffer.get(), mYuvIccImage.size,
- &width, &height, &icc, &exif));
-
- EXPECT_EQ(width, IMAGE_WIDTH);
- EXPECT_EQ(height, IMAGE_HEIGHT);
- EXPECT_GT(icc.size(), 0);
- EXPECT_GT(exif.size(), 0);
-
- EXPECT_EQ(IccHelper::readIccColorGamut(icc.data(), icc.size()), ULTRAHDR_COLORGAMUT_BT709);
+ EXPECT_TRUE(decoder.getCompressedImageParameters(mYuvIccImage.buffer.get(), mYuvIccImage.size));
+ EXPECT_EQ(IMAGE_WIDTH, decoder.getDecompressedImageWidth());
+ EXPECT_EQ(IMAGE_HEIGHT, decoder.getDecompressedImageHeight());
+ EXPECT_GT(decoder.getICCSize(), 0);
+ EXPECT_GT(decoder.getEXIFSize(), 0);
+ EXPECT_EQ(IccHelper::readIccColorGamut(decoder.getICCPtr(), decoder.getICCSize()),
+ ULTRAHDR_COLORGAMUT_BT709);
}
} // namespace ultrahdr
diff --git a/tests/jpegr_test.cpp b/tests/jpegr_test.cpp
index 39c7af0..0b420e6 100644
--- a/tests/jpegr_test.cpp
+++ b/tests/jpegr_test.cpp
@@ -302,9 +302,7 @@ static bool readFile(const char* fileName, void*& result, int maxLength, int& le
}
void decodeJpegRImg(jr_compressed_ptr img, [[maybe_unused]] const char* outFileName) {
- std::vector<uint8_t> iccData(0);
- std::vector<uint8_t> exifData(0);
- jpegr_info_struct info{0, 0, &iccData, &exifData};
+ jpegr_info_struct info{};
JpegR jpegHdr;
ASSERT_EQ(JPEGR_NO_ERROR, jpegHdr.getJPEGRInfo(img, &info));
ASSERT_EQ(kImageWidth, info.width);