blob: 7c669aba0afd3bf2865567c1d165f3ebc3f49e24 [file] [log] [blame]
Dichen Zhang85b37562022-10-11 11:08:28 -07001/*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Dichen Zhang761b52d2023-02-10 22:38:38 +000017#include <jpegrecoverymap/jpegr.h>
18#include <jpegrecoverymap/jpegrutils.h>
Harish Mahendrakar1e057282022-12-04 12:47:53 -080019#include <jpegrecoverymap/recoverymapmath.h>
Dichen Zhang36c1e732022-11-23 01:25:34 +000020#include <fcntl.h>
21#include <fstream>
22#include <gtest/gtest.h>
Nick Deakind19e5762023-02-10 15:39:08 -050023#include <sys/time.h>
Dichen Zhang36c1e732022-11-23 01:25:34 +000024#include <utils/Log.h>
25
26#define RAW_P010_IMAGE "/sdcard/Documents/raw_p010_image.p010"
Dichen Zhang7e3ed122022-12-14 22:05:01 +000027#define RAW_YUV420_IMAGE "/sdcard/Documents/raw_yuv420_image.yuv420"
Dichen Zhang36c1e732022-11-23 01:25:34 +000028#define JPEG_IMAGE "/sdcard/Documents/jpeg_image.jpg"
Dichen Zhang7e3ed122022-12-14 22:05:01 +000029#define TEST_IMAGE_WIDTH 1280
30#define TEST_IMAGE_HEIGHT 720
31#define DEFAULT_JPEG_QUALITY 90
Dichen Zhang36c1e732022-11-23 01:25:34 +000032
33#define SAVE_ENCODING_RESULT true
34#define SAVE_DECODING_RESULT true
Harish Mahendrakar1e057282022-12-04 12:47:53 -080035#define SAVE_INPUT_RGBA true
Dichen Zhang85b37562022-10-11 11:08:28 -070036
Dichen Zhangb2ed8302023-02-10 23:05:04 +000037namespace android::jpegrecoverymap {
Dichen Zhang85b37562022-10-11 11:08:28 -070038
Nick Deakind19e5762023-02-10 15:39:08 -050039struct Timer {
40 struct timeval StartingTime;
41 struct timeval EndingTime;
42 struct timeval ElapsedMicroseconds;
Nick Deakin594a4ca2022-11-16 20:57:42 -050043};
44
Nick Deakind19e5762023-02-10 15:39:08 -050045void timerStart(Timer *t) {
46 gettimeofday(&t->StartingTime, nullptr);
47}
Nick Deakin594a4ca2022-11-16 20:57:42 -050048
Nick Deakind19e5762023-02-10 15:39:08 -050049void timerStop(Timer *t) {
50 gettimeofday(&t->EndingTime, nullptr);
51}
52
53int64_t elapsedTime(Timer *t) {
54 t->ElapsedMicroseconds.tv_sec = t->EndingTime.tv_sec - t->StartingTime.tv_sec;
55 t->ElapsedMicroseconds.tv_usec = t->EndingTime.tv_usec - t->StartingTime.tv_usec;
56 return t->ElapsedMicroseconds.tv_sec * 1000000 + t->ElapsedMicroseconds.tv_usec;
Dichen Zhang36c1e732022-11-23 01:25:34 +000057}
58
59static size_t getFileSize(int fd) {
60 struct stat st;
61 if (fstat(fd, &st) < 0) {
62 ALOGW("%s : fstat failed", __func__);
63 return 0;
64 }
65 return st.st_size; // bytes
66}
67
68static bool loadFile(const char filename[], void*& result, int* fileLength) {
69 int fd = open(filename, O_CLOEXEC);
70 if (fd < 0) {
71 return false;
72 }
73 int length = getFileSize(fd);
74 if (length == 0) {
75 close(fd);
76 return false;
77 }
78 if (fileLength != nullptr) {
79 *fileLength = length;
80 }
81 result = malloc(length);
82 if (read(fd, result, length) != static_cast<ssize_t>(length)) {
83 close(fd);
84 return false;
85 }
86 close(fd);
87 return true;
88}
Nick Deakin594a4ca2022-11-16 20:57:42 -050089
Dichen Zhang761b52d2023-02-10 22:38:38 +000090class JpegRTest : public testing::Test {
Nick Deakind19e5762023-02-10 15:39:08 -050091public:
Dichen Zhang761b52d2023-02-10 22:38:38 +000092 JpegRTest();
93 ~JpegRTest();
Nick Deakind19e5762023-02-10 15:39:08 -050094
95protected:
96 virtual void SetUp();
97 virtual void TearDown();
98
99 struct jpegr_uncompressed_struct mRawP010Image;
100 struct jpegr_uncompressed_struct mRawYuv420Image;
101 struct jpegr_compressed_struct mJpegImage;
102};
103
Dichen Zhang761b52d2023-02-10 22:38:38 +0000104JpegRTest::JpegRTest() {}
105JpegRTest::~JpegRTest() {}
Nick Deakind19e5762023-02-10 15:39:08 -0500106
Dichen Zhang761b52d2023-02-10 22:38:38 +0000107void JpegRTest::SetUp() {}
108void JpegRTest::TearDown() {
Nick Deakind19e5762023-02-10 15:39:08 -0500109 free(mRawP010Image.data);
110 free(mRawYuv420Image.data);
111 free(mJpegImage.data);
112}
113
Dichen Zhang761b52d2023-02-10 22:38:38 +0000114class JpegRBenchmark : public JpegR {
Nick Deakind19e5762023-02-10 15:39:08 -0500115public:
116 void BenchmarkGenerateRecoveryMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr p010Image,
117 jr_metadata_ptr metadata, jr_uncompressed_ptr map);
118 void BenchmarkApplyRecoveryMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr map,
119 jr_metadata_ptr metadata, jr_uncompressed_ptr dest);
120private:
121 const int kProfileCount = 10;
122};
123
Dichen Zhang761b52d2023-02-10 22:38:38 +0000124void JpegRBenchmark::BenchmarkGenerateRecoveryMap(jr_uncompressed_ptr yuv420Image,
Nick Deakind19e5762023-02-10 15:39:08 -0500125 jr_uncompressed_ptr p010Image,
126 jr_metadata_ptr metadata,
127 jr_uncompressed_ptr map) {
128 ASSERT_EQ(yuv420Image->width, p010Image->width);
129 ASSERT_EQ(yuv420Image->height, p010Image->height);
130
131 Timer genRecMapTime;
132
133 timerStart(&genRecMapTime);
134 for (auto i = 0; i < kProfileCount; i++) {
135 ASSERT_EQ(OK, generateRecoveryMap(
136 yuv420Image, p010Image, jpegr_transfer_function::JPEGR_TF_HLG, metadata, map));
137 if (i != kProfileCount - 1) delete[] static_cast<uint8_t *>(map->data);
138 }
139 timerStop(&genRecMapTime);
140
141 ALOGE("Generate Recovery Map:- Res = %i x %i, time = %f ms",
142 yuv420Image->width, yuv420Image->height,
143 elapsedTime(&genRecMapTime) / (kProfileCount * 1000.f));
144
145}
146
Dichen Zhang761b52d2023-02-10 22:38:38 +0000147void JpegRBenchmark::BenchmarkApplyRecoveryMap(jr_uncompressed_ptr yuv420Image,
Nick Deakind19e5762023-02-10 15:39:08 -0500148 jr_uncompressed_ptr map,
149 jr_metadata_ptr metadata,
150 jr_uncompressed_ptr dest) {
151 Timer applyRecMapTime;
152
153 timerStart(&applyRecMapTime);
154 for (auto i = 0; i < kProfileCount; i++) {
Dichen Zhangc6605702023-03-15 18:40:55 -0700155 ASSERT_EQ(OK, applyRecoveryMap(yuv420Image, map, metadata, JPEGR_OUTPUT_HDR_HLG,
156 metadata->maxContentBoost /* displayBoost */, dest));
Nick Deakind19e5762023-02-10 15:39:08 -0500157 }
158 timerStop(&applyRecMapTime);
159
160 ALOGE("Apply Recovery Map:- Res = %i x %i, time = %f ms",
161 yuv420Image->width, yuv420Image->height,
162 elapsedTime(&applyRecMapTime) / (kProfileCount * 1000.f));
163}
164
Dichen Zhang761b52d2023-02-10 22:38:38 +0000165TEST_F(JpegRTest, build) {
Nick Deakin594a4ca2022-11-16 20:57:42 -0500166 // Force all of the recovery map lib to be linked by calling all public functions.
Dichen Zhang761b52d2023-02-10 22:38:38 +0000167 JpegR jpegRCodec;
168 jpegRCodec.encodeJPEGR(nullptr, static_cast<jpegr_transfer_function>(0), nullptr, 0, nullptr);
169 jpegRCodec.encodeJPEGR(nullptr, nullptr, static_cast<jpegr_transfer_function>(0),
170 nullptr, 0, nullptr);
171 jpegRCodec.encodeJPEGR(nullptr, nullptr, nullptr, static_cast<jpegr_transfer_function>(0),
172 nullptr);
173 jpegRCodec.encodeJPEGR(nullptr, nullptr, static_cast<jpegr_transfer_function>(0), nullptr);
Dichen Zhangc6605702023-03-15 18:40:55 -0700174 jpegRCodec.decodeJPEGR(nullptr, nullptr);
Nick Deakin594a4ca2022-11-16 20:57:42 -0500175}
176
Dichen Zhang761b52d2023-02-10 22:38:38 +0000177TEST_F(JpegRTest, writeXmpThenRead) {
Dichen Zhange286f1c2023-03-14 00:22:00 +0000178 jpegr_metadata_struct metadata_expected;
Nick Deakin01759062023-02-02 18:21:43 -0500179 metadata_expected.maxContentBoost = 1.25;
Nick Deakin3f89a3e2023-02-14 20:35:42 -0500180 metadata_expected.minContentBoost = 0.75;
Fyodor Kyslov8f46e2a2023-01-20 04:21:56 +0000181 const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
182 const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator
183
Dichen Zhang61ede362023-02-22 18:50:13 +0000184 std::string xmp = generateXmpForSecondaryImage(metadata_expected);
Dichen Zhangdc8452b2022-11-23 17:17:56 +0000185
Fyodor Kyslov8f46e2a2023-01-20 04:21:56 +0000186 std::vector<uint8_t> xmpData;
187 xmpData.reserve(nameSpaceLength + xmp.size());
188 xmpData.insert(xmpData.end(), reinterpret_cast<const uint8_t*>(nameSpace.c_str()),
189 reinterpret_cast<const uint8_t*>(nameSpace.c_str()) + nameSpaceLength);
190 xmpData.insert(xmpData.end(), reinterpret_cast<const uint8_t*>(xmp.c_str()),
191 reinterpret_cast<const uint8_t*>(xmp.c_str()) + xmp.size());
192
Dichen Zhange286f1c2023-03-14 00:22:00 +0000193 jpegr_metadata_struct metadata_read;
Fyodor Kyslov8f46e2a2023-01-20 04:21:56 +0000194 EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read));
Nick Deakin31f03e32023-03-31 16:00:13 -0400195 EXPECT_FLOAT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost);
196 EXPECT_FLOAT_EQ(metadata_expected.minContentBoost, metadata_read.minContentBoost);
Dichen Zhangdc8452b2022-11-23 17:17:56 +0000197}
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000198
199/* Test Encode API-0 and decode */
Dichen Zhang761b52d2023-02-10 22:38:38 +0000200TEST_F(JpegRTest, encodeFromP010ThenDecode) {
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800201 int ret;
202
203 // Load input files.
204 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
205 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
206 }
207 mRawP010Image.width = TEST_IMAGE_WIDTH;
208 mRawP010Image.height = TEST_IMAGE_HEIGHT;
209 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
210
Dichen Zhang761b52d2023-02-10 22:38:38 +0000211 JpegR jpegRCodec;
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800212
213 jpegr_compressed_struct jpegR;
214 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
215 jpegR.data = malloc(jpegR.maxLength);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000216 ret = jpegRCodec.encodeJPEGR(
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800217 &mRawP010Image, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR, DEFAULT_JPEG_QUALITY, nullptr);
218 if (ret != OK) {
219 FAIL() << "Error code is " << ret;
220 }
221 if (SAVE_ENCODING_RESULT) {
222 // Output image data to file
Dichen Zhang61ede362023-02-22 18:50:13 +0000223 std::string filePath = "/sdcard/Documents/encoded_from_p010_input.jpgr";
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800224 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
225 if (!imageFile.is_open()) {
226 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
227 }
228 imageFile.write((const char*)jpegR.data, jpegR.length);
229 }
230
231 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000232 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8;
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800233 decodedJpegR.data = malloc(decodedJpegRSize);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000234 ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR);
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800235 if (ret != OK) {
236 FAIL() << "Error code is " << ret;
237 }
238 if (SAVE_DECODING_RESULT) {
239 // Output image data to file
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000240 std::string filePath = "/sdcard/Documents/decoded_from_p010_input.rgb";
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800241 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
242 if (!imageFile.is_open()) {
243 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
244 }
245 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
246 }
247
248 free(jpegR.data);
249 free(decodedJpegR.data);
250}
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000251
252/* Test Encode API-1 and decode */
Dichen Zhang761b52d2023-02-10 22:38:38 +0000253TEST_F(JpegRTest, encodeFromRawHdrAndSdrThenDecode) {
Dichen Zhang54444382022-12-07 20:57:49 +0000254 int ret;
255
256 // Load input files.
257 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
258 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
259 }
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000260 mRawP010Image.width = TEST_IMAGE_WIDTH;
261 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhang54444382022-12-07 20:57:49 +0000262 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
263
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000264 if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
265 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
266 }
267 mRawYuv420Image.width = TEST_IMAGE_WIDTH;
268 mRawYuv420Image.height = TEST_IMAGE_HEIGHT;
269 mRawYuv420Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
270
Dichen Zhang761b52d2023-02-10 22:38:38 +0000271 JpegR jpegRCodec;
Dichen Zhang54444382022-12-07 20:57:49 +0000272
273 jpegr_compressed_struct jpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000274 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
Dichen Zhang54444382022-12-07 20:57:49 +0000275 jpegR.data = malloc(jpegR.maxLength);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000276 ret = jpegRCodec.encodeJPEGR(
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000277 &mRawP010Image, &mRawYuv420Image, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR,
278 DEFAULT_JPEG_QUALITY, nullptr);
Dichen Zhang54444382022-12-07 20:57:49 +0000279 if (ret != OK) {
280 FAIL() << "Error code is " << ret;
281 }
282 if (SAVE_ENCODING_RESULT) {
283 // Output image data to file
Dichen Zhang61ede362023-02-22 18:50:13 +0000284 std::string filePath = "/sdcard/Documents/encoded_from_p010_yuv420p_input.jpgr";
Dichen Zhang54444382022-12-07 20:57:49 +0000285 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
286 if (!imageFile.is_open()) {
287 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
288 }
289 imageFile.write((const char*)jpegR.data, jpegR.length);
290 }
291
292 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000293 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8;
Dichen Zhang54444382022-12-07 20:57:49 +0000294 decodedJpegR.data = malloc(decodedJpegRSize);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000295 ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR);
Dichen Zhang54444382022-12-07 20:57:49 +0000296 if (ret != OK) {
297 FAIL() << "Error code is " << ret;
298 }
299 if (SAVE_DECODING_RESULT) {
300 // Output image data to file
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000301 std::string filePath = "/sdcard/Documents/decoded_from_p010_yuv420p_input.rgb";
Dichen Zhang54444382022-12-07 20:57:49 +0000302 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
303 if (!imageFile.is_open()) {
304 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
305 }
306 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
307 }
308
309 free(jpegR.data);
310 free(decodedJpegR.data);
311}
312
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000313/* Test Encode API-2 and decode */
Dichen Zhang761b52d2023-02-10 22:38:38 +0000314TEST_F(JpegRTest, encodeFromRawHdrAndSdrAndJpegThenDecode) {
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000315 int ret;
316
317 // Load input files.
318 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
319 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
320 }
321 mRawP010Image.width = TEST_IMAGE_WIDTH;
322 mRawP010Image.height = TEST_IMAGE_HEIGHT;
323 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
324
325 if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
326 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
327 }
328 mRawYuv420Image.width = TEST_IMAGE_WIDTH;
329 mRawYuv420Image.height = TEST_IMAGE_HEIGHT;
330 mRawYuv420Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
331
332 if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) {
333 FAIL() << "Load file " << JPEG_IMAGE << " failed";
334 }
335 mJpegImage.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
336
Dichen Zhang761b52d2023-02-10 22:38:38 +0000337 JpegR jpegRCodec;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000338
339 jpegr_compressed_struct jpegR;
340 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
341 jpegR.data = malloc(jpegR.maxLength);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000342 ret = jpegRCodec.encodeJPEGR(
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000343 &mRawP010Image, &mRawYuv420Image, &mJpegImage, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR);
344 if (ret != OK) {
345 FAIL() << "Error code is " << ret;
346 }
347 if (SAVE_ENCODING_RESULT) {
348 // Output image data to file
Dichen Zhang61ede362023-02-22 18:50:13 +0000349 std::string filePath = "/sdcard/Documents/encoded_from_p010_yuv420p_jpeg_input.jpgr";
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000350 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
351 if (!imageFile.is_open()) {
352 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
353 }
354 imageFile.write((const char*)jpegR.data, jpegR.length);
355 }
356
357 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000358 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000359 decodedJpegR.data = malloc(decodedJpegRSize);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000360 ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR);
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000361 if (ret != OK) {
362 FAIL() << "Error code is " << ret;
363 }
364 if (SAVE_DECODING_RESULT) {
365 // Output image data to file
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000366 std::string filePath = "/sdcard/Documents/decoded_from_p010_yuv420p_jpeg_input.rgb";
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000367 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
368 if (!imageFile.is_open()) {
369 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
370 }
371 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
372 }
373
374 free(jpegR.data);
375 free(decodedJpegR.data);
376}
377
378/* Test Encode API-3 and decode */
Dichen Zhang761b52d2023-02-10 22:38:38 +0000379TEST_F(JpegRTest, encodeFromJpegThenDecode) {
Dichen Zhang36c1e732022-11-23 01:25:34 +0000380 int ret;
381
382 // Load input files.
383 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
384 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
385 }
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000386 mRawP010Image.width = TEST_IMAGE_WIDTH;
387 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000388 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
389
Harish Mahendrakar1e057282022-12-04 12:47:53 -0800390 if (SAVE_INPUT_RGBA) {
391 size_t rgbaSize = mRawP010Image.width * mRawP010Image.height * sizeof(uint32_t);
392 uint32_t *data = (uint32_t *)malloc(rgbaSize);
393
394 for (size_t y = 0; y < mRawP010Image.height; ++y) {
395 for (size_t x = 0; x < mRawP010Image.width; ++x) {
396 Color hdr_yuv_gamma = getP010Pixel(&mRawP010Image, x, y);
397 Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
398 uint32_t rgba1010102 = colorToRgba1010102(hdr_rgb_gamma);
399 size_t pixel_idx = x + y * mRawP010Image.width;
400 reinterpret_cast<uint32_t*>(data)[pixel_idx] = rgba1010102;
401 }
402 }
403
404 // Output image data to file
405 std::string filePath = "/sdcard/Documents/input_from_p010.rgb10";
406 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
407 if (!imageFile.is_open()) {
408 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
409 }
410 imageFile.write((const char*)data, rgbaSize);
411 free(data);
412 }
Dichen Zhang36c1e732022-11-23 01:25:34 +0000413 if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) {
414 FAIL() << "Load file " << JPEG_IMAGE << " failed";
415 }
416 mJpegImage.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
417
Dichen Zhang761b52d2023-02-10 22:38:38 +0000418 JpegR jpegRCodec;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000419
420 jpegr_compressed_struct jpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000421 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
Dichen Zhang36c1e732022-11-23 01:25:34 +0000422 jpegR.data = malloc(jpegR.maxLength);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000423 ret = jpegRCodec.encodeJPEGR(
Dichen Zhang36c1e732022-11-23 01:25:34 +0000424 &mRawP010Image, &mJpegImage, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR);
425 if (ret != OK) {
426 FAIL() << "Error code is " << ret;
427 }
428 if (SAVE_ENCODING_RESULT) {
429 // Output image data to file
Dichen Zhang61ede362023-02-22 18:50:13 +0000430 std::string filePath = "/sdcard/Documents/encoded_from_p010_jpeg_input.jpgr";
Dichen Zhang36c1e732022-11-23 01:25:34 +0000431 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
432 if (!imageFile.is_open()) {
433 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
434 }
435 imageFile.write((const char*)jpegR.data, jpegR.length);
436 }
437
438 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000439 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000440 decodedJpegR.data = malloc(decodedJpegRSize);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000441 ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR);
Dichen Zhang36c1e732022-11-23 01:25:34 +0000442 if (ret != OK) {
443 FAIL() << "Error code is " << ret;
444 }
445 if (SAVE_DECODING_RESULT) {
446 // Output image data to file
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000447 std::string filePath = "/sdcard/Documents/decoded_from_p010_jpeg_input.rgb";
Dichen Zhang36c1e732022-11-23 01:25:34 +0000448 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
449 if (!imageFile.is_open()) {
450 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
451 }
452 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
453 }
454
455 free(jpegR.data);
456 free(decodedJpegR.data);
457}
458
Dichen Zhang761b52d2023-02-10 22:38:38 +0000459TEST_F(JpegRTest, ProfileRecoveryMapFuncs) {
Nick Deakind19e5762023-02-10 15:39:08 -0500460 const size_t kWidth = TEST_IMAGE_WIDTH;
461 const size_t kHeight = TEST_IMAGE_HEIGHT;
462
463 // Load input files.
464 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
465 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
466 }
467 mRawP010Image.width = kWidth;
468 mRawP010Image.height = kHeight;
469 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
470
471 if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
472 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
473 }
474 mRawYuv420Image.width = kWidth;
475 mRawYuv420Image.height = kHeight;
476 mRawYuv420Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
477
Dichen Zhang761b52d2023-02-10 22:38:38 +0000478 JpegRBenchmark benchmark;
Nick Deakind19e5762023-02-10 15:39:08 -0500479
Dichen Zhange286f1c2023-03-14 00:22:00 +0000480 jpegr_metadata_struct metadata = { .version = 1,
Nick Deakind19e5762023-02-10 15:39:08 -0500481 .maxContentBoost = 8.0f,
482 .minContentBoost = 1.0f / 8.0f };
483
484 jpegr_uncompressed_struct map = { .data = NULL,
485 .width = 0,
486 .height = 0,
487 .colorGamut = JPEGR_COLORGAMUT_UNSPECIFIED };
488
489 benchmark.BenchmarkGenerateRecoveryMap(&mRawYuv420Image, &mRawP010Image, &metadata, &map);
490
491 const int dstSize = mRawYuv420Image.width * mRawYuv420Image.height * 4;
492 auto bufferDst = std::make_unique<uint8_t[]>(dstSize);
493 jpegr_uncompressed_struct dest = { .data = bufferDst.get(),
494 .width = 0,
495 .height = 0,
496 .colorGamut = JPEGR_COLORGAMUT_UNSPECIFIED };
497
498 benchmark.BenchmarkApplyRecoveryMap(&mRawYuv420Image, &map, &metadata, &dest);
499}
500
Nick Deakin3f89a3e2023-02-14 20:35:42 -0500501} // namespace android::recoverymap