blob: c3c6fd4e2b78c8073edf8dae5492c2ab36460d5a [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
17#include <jpegrecoverymap/recoverymap.h>
Dichen Zhangdc8452b2022-11-23 17:17:56 +000018#include <jpegrecoverymap/recoverymaputils.h>
Dichen Zhang36c1e732022-11-23 01:25:34 +000019#include <fcntl.h>
20#include <fstream>
21#include <gtest/gtest.h>
22#include <utils/Log.h>
23
24#define RAW_P010_IMAGE "/sdcard/Documents/raw_p010_image.p010"
Dichen Zhang7e3ed122022-12-14 22:05:01 +000025#define RAW_YUV420_IMAGE "/sdcard/Documents/raw_yuv420_image.yuv420"
Dichen Zhang36c1e732022-11-23 01:25:34 +000026#define JPEG_IMAGE "/sdcard/Documents/jpeg_image.jpg"
Dichen Zhang7e3ed122022-12-14 22:05:01 +000027#define TEST_IMAGE_WIDTH 1280
28#define TEST_IMAGE_HEIGHT 720
29#define DEFAULT_JPEG_QUALITY 90
Dichen Zhang36c1e732022-11-23 01:25:34 +000030
31#define SAVE_ENCODING_RESULT true
32#define SAVE_DECODING_RESULT true
Dichen Zhang85b37562022-10-11 11:08:28 -070033
Nick Deakin594a4ca2022-11-16 20:57:42 -050034namespace android::recoverymap {
Dichen Zhang85b37562022-10-11 11:08:28 -070035
Nick Deakin594a4ca2022-11-16 20:57:42 -050036class RecoveryMapTest : public testing::Test {
37public:
38 RecoveryMapTest();
39 ~RecoveryMapTest();
40protected:
41 virtual void SetUp();
42 virtual void TearDown();
Dichen Zhang36c1e732022-11-23 01:25:34 +000043
44 struct jpegr_uncompressed_struct mRawP010Image;
Dichen Zhang7e3ed122022-12-14 22:05:01 +000045 struct jpegr_uncompressed_struct mRawYuv420Image;
Dichen Zhang36c1e732022-11-23 01:25:34 +000046 struct jpegr_compressed_struct mJpegImage;
Nick Deakin594a4ca2022-11-16 20:57:42 -050047};
48
49RecoveryMapTest::RecoveryMapTest() {}
50RecoveryMapTest::~RecoveryMapTest() {}
51
52void RecoveryMapTest::SetUp() {}
Dichen Zhang36c1e732022-11-23 01:25:34 +000053void RecoveryMapTest::TearDown() {
54 free(mRawP010Image.data);
Dichen Zhang7e3ed122022-12-14 22:05:01 +000055 free(mRawYuv420Image.data);
Dichen Zhang36c1e732022-11-23 01:25:34 +000056 free(mJpegImage.data);
57}
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
90TEST_F(RecoveryMapTest, build) {
91 // Force all of the recovery map lib to be linked by calling all public functions.
92 RecoveryMap recovery_map;
Dichen Zhang636f5242022-12-07 20:25:44 +000093 recovery_map.encodeJPEGR(nullptr, static_cast<jpegr_transfer_function>(0), nullptr, 0, nullptr);
Nick Deakin6bd90432022-11-20 16:26:37 -050094 recovery_map.encodeJPEGR(nullptr, nullptr, static_cast<jpegr_transfer_function>(0),
95 nullptr, 0, nullptr);
96 recovery_map.encodeJPEGR(nullptr, nullptr, nullptr, static_cast<jpegr_transfer_function>(0),
97 nullptr);
98 recovery_map.encodeJPEGR(nullptr, nullptr, static_cast<jpegr_transfer_function>(0), nullptr);
Nick Deakin594a4ca2022-11-16 20:57:42 -050099 recovery_map.decodeJPEGR(nullptr, nullptr, nullptr, false);
100}
101
Dichen Zhangdc8452b2022-11-23 17:17:56 +0000102TEST_F(RecoveryMapTest, writeXmpThenRead) {
103 jpegr_metadata metadata_expected;
104 metadata_expected.transferFunction = JPEGR_TF_HLG;
105 metadata_expected.rangeScalingFactor = 1.25;
106 int length_expected = 1000;
107 std::string xmp = generateXmp(1000, metadata_expected);
108
109 jpegr_metadata metadata_read;
110 EXPECT_TRUE(getMetadataFromXMP(reinterpret_cast<uint8_t*>(xmp[0]), xmp.size(), &metadata_read));
111 ASSERT_EQ(metadata_expected.transferFunction, metadata_read.transferFunction);
112 ASSERT_EQ(metadata_expected.rangeScalingFactor, metadata_read.rangeScalingFactor);
113
114}
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000115
116/* Test Encode API-0 and decode */
117// TODO: enable when tonemapper is ready.
118//TEST_F(RecoveryMapTest, encodeFromP010ThenDecode) {
119// int ret;
120//
121// // Load input files.
122// if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
123// FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
124// }
125// mRawP010Image.width = TEST_IMAGE_WIDTH;
126// mRawP010Image.height = TEST_IMAGE_HEIGHT;
127// mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
128//
129// RecoveryMap recoveryMap;
130//
131// jpegr_compressed_struct jpegR;
132// jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
133// jpegR.data = malloc(jpegR.maxLength);
134// ret = recoveryMap.encodeJPEGR(
135// &mRawP010Image, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR, 90, nullptr);
136// if (ret != OK) {
137// FAIL() << "Error code is " << ret;
138// }
139// if (SAVE_ENCODING_RESULT) {
140// // Output image data to file
141// std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr";
142// std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
143// if (!imageFile.is_open()) {
144// ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
145// }
146// imageFile.write((const char*)jpegR.data, jpegR.length);
147// }
148//
149// jpegr_uncompressed_struct decodedJpegR;
150// int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 4;
151// decodedJpegR.data = malloc(decodedJpegRSize);
152// ret = recoveryMap.decodeJPEGR(&jpegR, &decodedJpegR);
153// if (ret != OK) {
154// FAIL() << "Error code is " << ret;
155// }
156// if (SAVE_DECODING_RESULT) {
157// // Output image data to file
158// std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10";
159// std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
160// if (!imageFile.is_open()) {
161// ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
162// }
163// imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
164// }
165//
166// free(jpegR.data);
167// free(decodedJpegR.data);
168//}
169
170/* Test Encode API-1 and decode */
171TEST_F(RecoveryMapTest, encodeFromRawHdrAndSdrThenDecode) {
Dichen Zhang54444382022-12-07 20:57:49 +0000172 int ret;
173
174 // Load input files.
175 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
176 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
177 }
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000178 mRawP010Image.width = TEST_IMAGE_WIDTH;
179 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhang54444382022-12-07 20:57:49 +0000180 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
181
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000182 if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
183 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
184 }
185 mRawYuv420Image.width = TEST_IMAGE_WIDTH;
186 mRawYuv420Image.height = TEST_IMAGE_HEIGHT;
187 mRawYuv420Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
188
Dichen Zhang54444382022-12-07 20:57:49 +0000189 RecoveryMap recoveryMap;
190
191 jpegr_compressed_struct jpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000192 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
Dichen Zhang54444382022-12-07 20:57:49 +0000193 jpegR.data = malloc(jpegR.maxLength);
194 ret = recoveryMap.encodeJPEGR(
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000195 &mRawP010Image, &mRawYuv420Image, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR,
196 DEFAULT_JPEG_QUALITY, nullptr);
Dichen Zhang54444382022-12-07 20:57:49 +0000197 if (ret != OK) {
198 FAIL() << "Error code is " << ret;
199 }
200 if (SAVE_ENCODING_RESULT) {
201 // Output image data to file
202 std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr";
203 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
204 if (!imageFile.is_open()) {
205 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
206 }
207 imageFile.write((const char*)jpegR.data, jpegR.length);
208 }
209
210 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000211 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 4;
Dichen Zhang54444382022-12-07 20:57:49 +0000212 decodedJpegR.data = malloc(decodedJpegRSize);
213 ret = recoveryMap.decodeJPEGR(&jpegR, &decodedJpegR);
214 if (ret != OK) {
215 FAIL() << "Error code is " << ret;
216 }
217 if (SAVE_DECODING_RESULT) {
218 // Output image data to file
219 std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10";
220 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
221 if (!imageFile.is_open()) {
222 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
223 }
224 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
225 }
226
227 free(jpegR.data);
228 free(decodedJpegR.data);
229}
230
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000231/* Test Encode API-2 and decode */
232TEST_F(RecoveryMapTest, encodeFromRawHdrAndSdrAndJpegThenDecode) {
233 int ret;
234
235 // Load input files.
236 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
237 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
238 }
239 mRawP010Image.width = TEST_IMAGE_WIDTH;
240 mRawP010Image.height = TEST_IMAGE_HEIGHT;
241 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
242
243 if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
244 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
245 }
246 mRawYuv420Image.width = TEST_IMAGE_WIDTH;
247 mRawYuv420Image.height = TEST_IMAGE_HEIGHT;
248 mRawYuv420Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
249
250 if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) {
251 FAIL() << "Load file " << JPEG_IMAGE << " failed";
252 }
253 mJpegImage.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
254
255 RecoveryMap recoveryMap;
256
257 jpegr_compressed_struct jpegR;
258 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
259 jpegR.data = malloc(jpegR.maxLength);
260 ret = recoveryMap.encodeJPEGR(
261 &mRawP010Image, &mRawYuv420Image, &mJpegImage, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR);
262 if (ret != OK) {
263 FAIL() << "Error code is " << ret;
264 }
265 if (SAVE_ENCODING_RESULT) {
266 // Output image data to file
267 std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr";
268 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
269 if (!imageFile.is_open()) {
270 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
271 }
272 imageFile.write((const char*)jpegR.data, jpegR.length);
273 }
274
275 jpegr_uncompressed_struct decodedJpegR;
276 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 4;
277 decodedJpegR.data = malloc(decodedJpegRSize);
278 ret = recoveryMap.decodeJPEGR(&jpegR, &decodedJpegR);
279 if (ret != OK) {
280 FAIL() << "Error code is " << ret;
281 }
282 if (SAVE_DECODING_RESULT) {
283 // Output image data to file
284 std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10";
285 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*)decodedJpegR.data, decodedJpegRSize);
290 }
291
292 free(jpegR.data);
293 free(decodedJpegR.data);
294}
295
296/* Test Encode API-3 and decode */
Dichen Zhang36c1e732022-11-23 01:25:34 +0000297TEST_F(RecoveryMapTest, encodeFromJpegThenDecode) {
298 int ret;
299
300 // Load input files.
301 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
302 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
303 }
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000304 mRawP010Image.width = TEST_IMAGE_WIDTH;
305 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000306 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
307
308 if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) {
309 FAIL() << "Load file " << JPEG_IMAGE << " failed";
310 }
311 mJpegImage.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
312
313 RecoveryMap recoveryMap;
314
315 jpegr_compressed_struct jpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000316 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
Dichen Zhang36c1e732022-11-23 01:25:34 +0000317 jpegR.data = malloc(jpegR.maxLength);
318 ret = recoveryMap.encodeJPEGR(
319 &mRawP010Image, &mJpegImage, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR);
320 if (ret != OK) {
321 FAIL() << "Error code is " << ret;
322 }
323 if (SAVE_ENCODING_RESULT) {
324 // Output image data to file
325 std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr";
326 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
327 if (!imageFile.is_open()) {
328 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
329 }
330 imageFile.write((const char*)jpegR.data, jpegR.length);
331 }
332
333 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000334 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 4;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000335 decodedJpegR.data = malloc(decodedJpegRSize);
336 ret = recoveryMap.decodeJPEGR(&jpegR, &decodedJpegR);
337 if (ret != OK) {
338 FAIL() << "Error code is " << ret;
339 }
340 if (SAVE_DECODING_RESULT) {
341 // Output image data to file
342 std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10";
343 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
344 if (!imageFile.is_open()) {
345 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
346 }
347 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
348 }
349
350 free(jpegR.data);
351 free(decodedJpegR.data);
352}
353
Nick Deakin594a4ca2022-11-16 20:57:42 -0500354} // namespace android::recoverymap