blob: 8ff12fb528793c78f8a9e276918fbdc6762ac6bb [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 */
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800117TEST_F(RecoveryMapTest, encodeFromP010ThenDecode) {
118 int ret;
119
120 // Load input files.
121 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
122 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
123 }
124 mRawP010Image.width = TEST_IMAGE_WIDTH;
125 mRawP010Image.height = TEST_IMAGE_HEIGHT;
126 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
127
128 RecoveryMap recoveryMap;
129
130 jpegr_compressed_struct jpegR;
131 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
132 jpegR.data = malloc(jpegR.maxLength);
133 ret = recoveryMap.encodeJPEGR(
134 &mRawP010Image, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR, DEFAULT_JPEG_QUALITY, nullptr);
135 if (ret != OK) {
136 FAIL() << "Error code is " << ret;
137 }
138 if (SAVE_ENCODING_RESULT) {
139 // Output image data to file
140 std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr";
141 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
142 if (!imageFile.is_open()) {
143 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
144 }
145 imageFile.write((const char*)jpegR.data, jpegR.length);
146 }
147
148 jpegr_uncompressed_struct decodedJpegR;
149 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 4;
150 decodedJpegR.data = malloc(decodedJpegRSize);
151 ret = recoveryMap.decodeJPEGR(&jpegR, &decodedJpegR);
152 if (ret != OK) {
153 FAIL() << "Error code is " << ret;
154 }
155 if (SAVE_DECODING_RESULT) {
156 // Output image data to file
157 std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10";
158 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
159 if (!imageFile.is_open()) {
160 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
161 }
162 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
163 }
164
165 free(jpegR.data);
166 free(decodedJpegR.data);
167}
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000168
169/* Test Encode API-1 and decode */
170TEST_F(RecoveryMapTest, encodeFromRawHdrAndSdrThenDecode) {
Dichen Zhang54444382022-12-07 20:57:49 +0000171 int ret;
172
173 // Load input files.
174 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
175 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
176 }
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000177 mRawP010Image.width = TEST_IMAGE_WIDTH;
178 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhang54444382022-12-07 20:57:49 +0000179 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
180
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000181 if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
182 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
183 }
184 mRawYuv420Image.width = TEST_IMAGE_WIDTH;
185 mRawYuv420Image.height = TEST_IMAGE_HEIGHT;
186 mRawYuv420Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
187
Dichen Zhang54444382022-12-07 20:57:49 +0000188 RecoveryMap recoveryMap;
189
190 jpegr_compressed_struct jpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000191 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
Dichen Zhang54444382022-12-07 20:57:49 +0000192 jpegR.data = malloc(jpegR.maxLength);
193 ret = recoveryMap.encodeJPEGR(
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000194 &mRawP010Image, &mRawYuv420Image, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR,
195 DEFAULT_JPEG_QUALITY, nullptr);
Dichen Zhang54444382022-12-07 20:57:49 +0000196 if (ret != OK) {
197 FAIL() << "Error code is " << ret;
198 }
199 if (SAVE_ENCODING_RESULT) {
200 // Output image data to file
201 std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr";
202 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
203 if (!imageFile.is_open()) {
204 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
205 }
206 imageFile.write((const char*)jpegR.data, jpegR.length);
207 }
208
209 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000210 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 4;
Dichen Zhang54444382022-12-07 20:57:49 +0000211 decodedJpegR.data = malloc(decodedJpegRSize);
212 ret = recoveryMap.decodeJPEGR(&jpegR, &decodedJpegR);
213 if (ret != OK) {
214 FAIL() << "Error code is " << ret;
215 }
216 if (SAVE_DECODING_RESULT) {
217 // Output image data to file
218 std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10";
219 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
220 if (!imageFile.is_open()) {
221 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
222 }
223 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
224 }
225
226 free(jpegR.data);
227 free(decodedJpegR.data);
228}
229
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000230/* Test Encode API-2 and decode */
231TEST_F(RecoveryMapTest, encodeFromRawHdrAndSdrAndJpegThenDecode) {
232 int ret;
233
234 // Load input files.
235 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
236 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
237 }
238 mRawP010Image.width = TEST_IMAGE_WIDTH;
239 mRawP010Image.height = TEST_IMAGE_HEIGHT;
240 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
241
242 if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
243 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
244 }
245 mRawYuv420Image.width = TEST_IMAGE_WIDTH;
246 mRawYuv420Image.height = TEST_IMAGE_HEIGHT;
247 mRawYuv420Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
248
249 if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) {
250 FAIL() << "Load file " << JPEG_IMAGE << " failed";
251 }
252 mJpegImage.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
253
254 RecoveryMap recoveryMap;
255
256 jpegr_compressed_struct jpegR;
257 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
258 jpegR.data = malloc(jpegR.maxLength);
259 ret = recoveryMap.encodeJPEGR(
260 &mRawP010Image, &mRawYuv420Image, &mJpegImage, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR);
261 if (ret != OK) {
262 FAIL() << "Error code is " << ret;
263 }
264 if (SAVE_ENCODING_RESULT) {
265 // Output image data to file
266 std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr";
267 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
268 if (!imageFile.is_open()) {
269 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
270 }
271 imageFile.write((const char*)jpegR.data, jpegR.length);
272 }
273
274 jpegr_uncompressed_struct decodedJpegR;
275 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 4;
276 decodedJpegR.data = malloc(decodedJpegRSize);
277 ret = recoveryMap.decodeJPEGR(&jpegR, &decodedJpegR);
278 if (ret != OK) {
279 FAIL() << "Error code is " << ret;
280 }
281 if (SAVE_DECODING_RESULT) {
282 // Output image data to file
283 std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10";
284 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
285 if (!imageFile.is_open()) {
286 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
287 }
288 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
289 }
290
291 free(jpegR.data);
292 free(decodedJpegR.data);
293}
294
295/* Test Encode API-3 and decode */
Dichen Zhang36c1e732022-11-23 01:25:34 +0000296TEST_F(RecoveryMapTest, encodeFromJpegThenDecode) {
297 int ret;
298
299 // Load input files.
300 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
301 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
302 }
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000303 mRawP010Image.width = TEST_IMAGE_WIDTH;
304 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000305 mRawP010Image.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
306
307 if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) {
308 FAIL() << "Load file " << JPEG_IMAGE << " failed";
309 }
310 mJpegImage.colorGamut = jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
311
312 RecoveryMap recoveryMap;
313
314 jpegr_compressed_struct jpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000315 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
Dichen Zhang36c1e732022-11-23 01:25:34 +0000316 jpegR.data = malloc(jpegR.maxLength);
317 ret = recoveryMap.encodeJPEGR(
318 &mRawP010Image, &mJpegImage, jpegr_transfer_function::JPEGR_TF_HLG, &jpegR);
319 if (ret != OK) {
320 FAIL() << "Error code is " << ret;
321 }
322 if (SAVE_ENCODING_RESULT) {
323 // Output image data to file
324 std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr";
325 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
326 if (!imageFile.is_open()) {
327 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
328 }
329 imageFile.write((const char*)jpegR.data, jpegR.length);
330 }
331
332 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000333 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 4;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000334 decodedJpegR.data = malloc(decodedJpegRSize);
335 ret = recoveryMap.decodeJPEGR(&jpegR, &decodedJpegR);
336 if (ret != OK) {
337 FAIL() << "Error code is " << ret;
338 }
339 if (SAVE_DECODING_RESULT) {
340 // Output image data to file
341 std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10";
342 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
343 if (!imageFile.is_open()) {
344 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
345 }
346 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
347 }
348
349 free(jpegR.data);
350 free(decodedJpegR.data);
351}
352
Nick Deakin594a4ca2022-11-16 20:57:42 -0500353} // namespace android::recoverymap