blob: 58cd8f4711386960666102f2acae956a5f0b3b90 [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 Zhangdbceb0e2023-04-14 19:03:18 +000017#include <ultrahdr/jpegr.h>
18#include <ultrahdr/jpegrutils.h>
19#include <ultrahdr/gainmapmath.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 Zhang66ca6e32023-04-05 12:22:54 -070027#define RAW_P010_IMAGE_WITH_STRIDE "/sdcard/Documents/raw_p010_image_with_stride.p010"
Dichen Zhang7e3ed122022-12-14 22:05:01 +000028#define RAW_YUV420_IMAGE "/sdcard/Documents/raw_yuv420_image.yuv420"
Dichen Zhang36c1e732022-11-23 01:25:34 +000029#define JPEG_IMAGE "/sdcard/Documents/jpeg_image.jpg"
Dichen Zhang7e3ed122022-12-14 22:05:01 +000030#define TEST_IMAGE_WIDTH 1280
31#define TEST_IMAGE_HEIGHT 720
Dichen Zhang66ca6e32023-04-05 12:22:54 -070032#define TEST_IMAGE_STRIDE 1288
Dichen Zhang7e3ed122022-12-14 22:05:01 +000033#define DEFAULT_JPEG_QUALITY 90
Dichen Zhang36c1e732022-11-23 01:25:34 +000034
35#define SAVE_ENCODING_RESULT true
36#define SAVE_DECODING_RESULT true
Harish Mahendrakar1e057282022-12-04 12:47:53 -080037#define SAVE_INPUT_RGBA true
Dichen Zhang85b37562022-10-11 11:08:28 -070038
Dichen Zhangdbceb0e2023-04-14 19:03:18 +000039namespace android::ultrahdr {
Dichen Zhang85b37562022-10-11 11:08:28 -070040
Nick Deakind19e5762023-02-10 15:39:08 -050041struct Timer {
42 struct timeval StartingTime;
43 struct timeval EndingTime;
44 struct timeval ElapsedMicroseconds;
Nick Deakin594a4ca2022-11-16 20:57:42 -050045};
46
Nick Deakind19e5762023-02-10 15:39:08 -050047void timerStart(Timer *t) {
48 gettimeofday(&t->StartingTime, nullptr);
49}
Nick Deakin594a4ca2022-11-16 20:57:42 -050050
Nick Deakind19e5762023-02-10 15:39:08 -050051void timerStop(Timer *t) {
52 gettimeofday(&t->EndingTime, nullptr);
53}
54
55int64_t elapsedTime(Timer *t) {
56 t->ElapsedMicroseconds.tv_sec = t->EndingTime.tv_sec - t->StartingTime.tv_sec;
57 t->ElapsedMicroseconds.tv_usec = t->EndingTime.tv_usec - t->StartingTime.tv_usec;
58 return t->ElapsedMicroseconds.tv_sec * 1000000 + t->ElapsedMicroseconds.tv_usec;
Dichen Zhang36c1e732022-11-23 01:25:34 +000059}
60
61static size_t getFileSize(int fd) {
62 struct stat st;
63 if (fstat(fd, &st) < 0) {
64 ALOGW("%s : fstat failed", __func__);
65 return 0;
66 }
67 return st.st_size; // bytes
68}
69
70static bool loadFile(const char filename[], void*& result, int* fileLength) {
71 int fd = open(filename, O_CLOEXEC);
72 if (fd < 0) {
73 return false;
74 }
75 int length = getFileSize(fd);
76 if (length == 0) {
77 close(fd);
78 return false;
79 }
80 if (fileLength != nullptr) {
81 *fileLength = length;
82 }
83 result = malloc(length);
84 if (read(fd, result, length) != static_cast<ssize_t>(length)) {
85 close(fd);
86 return false;
87 }
88 close(fd);
89 return true;
90}
Nick Deakin594a4ca2022-11-16 20:57:42 -050091
Dichen Zhang761b52d2023-02-10 22:38:38 +000092class JpegRTest : public testing::Test {
Nick Deakind19e5762023-02-10 15:39:08 -050093public:
Dichen Zhang761b52d2023-02-10 22:38:38 +000094 JpegRTest();
95 ~JpegRTest();
Nick Deakind19e5762023-02-10 15:39:08 -050096
97protected:
98 virtual void SetUp();
99 virtual void TearDown();
100
101 struct jpegr_uncompressed_struct mRawP010Image;
Dichen Zhang66ca6e32023-04-05 12:22:54 -0700102 struct jpegr_uncompressed_struct mRawP010ImageWithStride;
Nick Deakind19e5762023-02-10 15:39:08 -0500103 struct jpegr_uncompressed_struct mRawYuv420Image;
104 struct jpegr_compressed_struct mJpegImage;
105};
106
Dichen Zhang761b52d2023-02-10 22:38:38 +0000107JpegRTest::JpegRTest() {}
108JpegRTest::~JpegRTest() {}
Nick Deakind19e5762023-02-10 15:39:08 -0500109
Dichen Zhang761b52d2023-02-10 22:38:38 +0000110void JpegRTest::SetUp() {}
111void JpegRTest::TearDown() {
Nick Deakind19e5762023-02-10 15:39:08 -0500112 free(mRawP010Image.data);
Dichen Zhang66ca6e32023-04-05 12:22:54 -0700113 free(mRawP010ImageWithStride.data);
Nick Deakind19e5762023-02-10 15:39:08 -0500114 free(mRawYuv420Image.data);
115 free(mJpegImage.data);
116}
117
Dichen Zhang761b52d2023-02-10 22:38:38 +0000118class JpegRBenchmark : public JpegR {
Nick Deakind19e5762023-02-10 15:39:08 -0500119public:
Dichen Zhang10959a42023-04-10 16:28:16 -0700120 void BenchmarkGenerateGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr p010Image,
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000121 ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr map);
Dichen Zhang10959a42023-04-10 16:28:16 -0700122 void BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr map,
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000123 ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr dest);
Nick Deakind19e5762023-02-10 15:39:08 -0500124private:
125 const int kProfileCount = 10;
126};
127
Dichen Zhang10959a42023-04-10 16:28:16 -0700128void JpegRBenchmark::BenchmarkGenerateGainMap(jr_uncompressed_ptr yuv420Image,
129 jr_uncompressed_ptr p010Image,
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000130 ultrahdr_metadata_ptr metadata,
Dichen Zhang10959a42023-04-10 16:28:16 -0700131 jr_uncompressed_ptr map) {
Nick Deakind19e5762023-02-10 15:39:08 -0500132 ASSERT_EQ(yuv420Image->width, p010Image->width);
133 ASSERT_EQ(yuv420Image->height, p010Image->height);
134
135 Timer genRecMapTime;
136
137 timerStart(&genRecMapTime);
138 for (auto i = 0; i < kProfileCount; i++) {
Dichen Zhang10959a42023-04-10 16:28:16 -0700139 ASSERT_EQ(OK, generateGainMap(
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000140 yuv420Image, p010Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, metadata, map));
Nick Deakind19e5762023-02-10 15:39:08 -0500141 if (i != kProfileCount - 1) delete[] static_cast<uint8_t *>(map->data);
142 }
143 timerStop(&genRecMapTime);
144
Dichen Zhang10959a42023-04-10 16:28:16 -0700145 ALOGE("Generate Gain Map:- Res = %i x %i, time = %f ms",
Nick Deakind19e5762023-02-10 15:39:08 -0500146 yuv420Image->width, yuv420Image->height,
147 elapsedTime(&genRecMapTime) / (kProfileCount * 1000.f));
148
149}
150
Dichen Zhang10959a42023-04-10 16:28:16 -0700151void JpegRBenchmark::BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image,
152 jr_uncompressed_ptr map,
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000153 ultrahdr_metadata_ptr metadata,
Dichen Zhang10959a42023-04-10 16:28:16 -0700154 jr_uncompressed_ptr dest) {
Nick Deakind19e5762023-02-10 15:39:08 -0500155 Timer applyRecMapTime;
156
157 timerStart(&applyRecMapTime);
158 for (auto i = 0; i < kProfileCount; i++) {
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000159 ASSERT_EQ(OK, applyGainMap(yuv420Image, map, metadata, ULTRAHDR_OUTPUT_HDR_HLG,
Dichen Zhang10959a42023-04-10 16:28:16 -0700160 metadata->maxContentBoost /* displayBoost */, dest));
Nick Deakind19e5762023-02-10 15:39:08 -0500161 }
162 timerStop(&applyRecMapTime);
163
Dichen Zhang10959a42023-04-10 16:28:16 -0700164 ALOGE("Apply Gain Map:- Res = %i x %i, time = %f ms",
Nick Deakind19e5762023-02-10 15:39:08 -0500165 yuv420Image->width, yuv420Image->height,
166 elapsedTime(&applyRecMapTime) / (kProfileCount * 1000.f));
167}
168
Dichen Zhang761b52d2023-02-10 22:38:38 +0000169TEST_F(JpegRTest, build) {
Dichen Zhang10959a42023-04-10 16:28:16 -0700170 // Force all of the gain map lib to be linked by calling all public functions.
Dichen Zhang761b52d2023-02-10 22:38:38 +0000171 JpegR jpegRCodec;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000172 jpegRCodec.encodeJPEGR(nullptr, static_cast<ultrahdr_transfer_function>(0), nullptr, 0, nullptr);
173 jpegRCodec.encodeJPEGR(nullptr, nullptr, static_cast<ultrahdr_transfer_function>(0),
Dichen Zhang761b52d2023-02-10 22:38:38 +0000174 nullptr, 0, nullptr);
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000175 jpegRCodec.encodeJPEGR(nullptr, nullptr, nullptr, static_cast<ultrahdr_transfer_function>(0),
Dichen Zhang761b52d2023-02-10 22:38:38 +0000176 nullptr);
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000177 jpegRCodec.encodeJPEGR(nullptr, nullptr, static_cast<ultrahdr_transfer_function>(0), nullptr);
Dichen Zhangc6605702023-03-15 18:40:55 -0700178 jpegRCodec.decodeJPEGR(nullptr, nullptr);
Nick Deakin594a4ca2022-11-16 20:57:42 -0500179}
180
Dichen Zhang761b52d2023-02-10 22:38:38 +0000181TEST_F(JpegRTest, writeXmpThenRead) {
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000182 ultrahdr_metadata_struct metadata_expected;
Nick Deakin05ceebf2023-04-19 15:27:13 -0400183 metadata_expected.version = "1.0";
Nick Deakin01759062023-02-02 18:21:43 -0500184 metadata_expected.maxContentBoost = 1.25;
Nick Deakin3f89a3e2023-02-14 20:35:42 -0500185 metadata_expected.minContentBoost = 0.75;
Fyodor Kyslov8f46e2a2023-01-20 04:21:56 +0000186 const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
187 const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator
188
Dichen Zhang61ede362023-02-22 18:50:13 +0000189 std::string xmp = generateXmpForSecondaryImage(metadata_expected);
Dichen Zhangdc8452b2022-11-23 17:17:56 +0000190
Fyodor Kyslov8f46e2a2023-01-20 04:21:56 +0000191 std::vector<uint8_t> xmpData;
192 xmpData.reserve(nameSpaceLength + xmp.size());
193 xmpData.insert(xmpData.end(), reinterpret_cast<const uint8_t*>(nameSpace.c_str()),
194 reinterpret_cast<const uint8_t*>(nameSpace.c_str()) + nameSpaceLength);
195 xmpData.insert(xmpData.end(), reinterpret_cast<const uint8_t*>(xmp.c_str()),
196 reinterpret_cast<const uint8_t*>(xmp.c_str()) + xmp.size());
197
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000198 ultrahdr_metadata_struct metadata_read;
Fyodor Kyslov8f46e2a2023-01-20 04:21:56 +0000199 EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read));
Nick Deakin31f03e32023-03-31 16:00:13 -0400200 EXPECT_FLOAT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost);
201 EXPECT_FLOAT_EQ(metadata_expected.minContentBoost, metadata_read.minContentBoost);
Dichen Zhangdc8452b2022-11-23 17:17:56 +0000202}
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000203
204/* Test Encode API-0 and decode */
Dichen Zhang761b52d2023-02-10 22:38:38 +0000205TEST_F(JpegRTest, encodeFromP010ThenDecode) {
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800206 int ret;
207
208 // Load input files.
209 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
210 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
211 }
212 mRawP010Image.width = TEST_IMAGE_WIDTH;
213 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000214 mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800215
Dichen Zhang761b52d2023-02-10 22:38:38 +0000216 JpegR jpegRCodec;
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800217
218 jpegr_compressed_struct jpegR;
219 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
220 jpegR.data = malloc(jpegR.maxLength);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000221 ret = jpegRCodec.encodeJPEGR(
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000222 &mRawP010Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, DEFAULT_JPEG_QUALITY,
223 nullptr);
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800224 if (ret != OK) {
225 FAIL() << "Error code is " << ret;
226 }
227 if (SAVE_ENCODING_RESULT) {
228 // Output image data to file
Dichen Zhang61ede362023-02-22 18:50:13 +0000229 std::string filePath = "/sdcard/Documents/encoded_from_p010_input.jpgr";
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800230 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
231 if (!imageFile.is_open()) {
232 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
233 }
234 imageFile.write((const char*)jpegR.data, jpegR.length);
235 }
236
237 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000238 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8;
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800239 decodedJpegR.data = malloc(decodedJpegRSize);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000240 ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR);
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800241 if (ret != OK) {
242 FAIL() << "Error code is " << ret;
243 }
244 if (SAVE_DECODING_RESULT) {
245 // Output image data to file
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000246 std::string filePath = "/sdcard/Documents/decoded_from_p010_input.rgb";
Dichen Zhangc3437ca2023-01-04 14:00:08 -0800247 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
248 if (!imageFile.is_open()) {
249 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
250 }
251 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
252 }
253
254 free(jpegR.data);
255 free(decodedJpegR.data);
256}
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000257
Dichen Zhang66ca6e32023-04-05 12:22:54 -0700258/* Test Encode API-0 (with stride) and decode */
259TEST_F(JpegRTest, encodeFromP010WithStrideThenDecode) {
260 int ret;
261
262 // Load input files.
263 if (!loadFile(RAW_P010_IMAGE_WITH_STRIDE, mRawP010ImageWithStride.data, nullptr)) {
264 FAIL() << "Load file " << RAW_P010_IMAGE_WITH_STRIDE << " failed";
265 }
266 mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH;
267 mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT;
268 mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000269 mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
Dichen Zhang66ca6e32023-04-05 12:22:54 -0700270
271 JpegR jpegRCodec;
272
273 jpegr_compressed_struct jpegR;
274 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
275 jpegR.data = malloc(jpegR.maxLength);
276 ret = jpegRCodec.encodeJPEGR(
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000277 &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR,
Dichen Zhang66ca6e32023-04-05 12:22:54 -0700278 DEFAULT_JPEG_QUALITY, nullptr);
279 if (ret != OK) {
280 FAIL() << "Error code is " << ret;
281 }
282 if (SAVE_ENCODING_RESULT) {
283 // Output image data to file
284 std::string filePath = "/sdcard/Documents/encoded_from_p010_input.jpgr";
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*)jpegR.data, jpegR.length);
290 }
291
292 jpegr_uncompressed_struct decodedJpegR;
293 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8;
294 decodedJpegR.data = malloc(decodedJpegRSize);
295 ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR);
296 if (ret != OK) {
297 FAIL() << "Error code is " << ret;
298 }
299 if (SAVE_DECODING_RESULT) {
300 // Output image data to file
301 std::string filePath = "/sdcard/Documents/decoded_from_p010_input.rgb";
302 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-1 and decode */
Dichen Zhang761b52d2023-02-10 22:38:38 +0000314TEST_F(JpegRTest, encodeFromRawHdrAndSdrThenDecode) {
Dichen Zhang54444382022-12-07 20:57:49 +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 }
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000321 mRawP010Image.width = TEST_IMAGE_WIDTH;
322 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000323 mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
Dichen Zhang54444382022-12-07 20:57:49 +0000324
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000325 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;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000330 mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000331
Dichen Zhang761b52d2023-02-10 22:38:38 +0000332 JpegR jpegRCodec;
Dichen Zhang54444382022-12-07 20:57:49 +0000333
334 jpegr_compressed_struct jpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000335 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
Dichen Zhang54444382022-12-07 20:57:49 +0000336 jpegR.data = malloc(jpegR.maxLength);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000337 ret = jpegRCodec.encodeJPEGR(
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000338 &mRawP010Image, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR,
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000339 DEFAULT_JPEG_QUALITY, nullptr);
Dichen Zhang54444382022-12-07 20:57:49 +0000340 if (ret != OK) {
341 FAIL() << "Error code is " << ret;
342 }
343 if (SAVE_ENCODING_RESULT) {
344 // Output image data to file
Dichen Zhang61ede362023-02-22 18:50:13 +0000345 std::string filePath = "/sdcard/Documents/encoded_from_p010_yuv420p_input.jpgr";
Dichen Zhang54444382022-12-07 20:57:49 +0000346 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
347 if (!imageFile.is_open()) {
348 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
349 }
350 imageFile.write((const char*)jpegR.data, jpegR.length);
351 }
352
353 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000354 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8;
Dichen Zhang54444382022-12-07 20:57:49 +0000355 decodedJpegR.data = malloc(decodedJpegRSize);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000356 ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR);
Dichen Zhang54444382022-12-07 20:57:49 +0000357 if (ret != OK) {
358 FAIL() << "Error code is " << ret;
359 }
360 if (SAVE_DECODING_RESULT) {
361 // Output image data to file
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000362 std::string filePath = "/sdcard/Documents/decoded_from_p010_yuv420p_input.rgb";
Dichen Zhang54444382022-12-07 20:57:49 +0000363 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
364 if (!imageFile.is_open()) {
365 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
366 }
367 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
368 }
369
370 free(jpegR.data);
371 free(decodedJpegR.data);
372}
373
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000374/* Test Encode API-2 and decode */
Dichen Zhang761b52d2023-02-10 22:38:38 +0000375TEST_F(JpegRTest, encodeFromRawHdrAndSdrAndJpegThenDecode) {
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000376 int ret;
377
378 // Load input files.
379 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
380 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
381 }
382 mRawP010Image.width = TEST_IMAGE_WIDTH;
383 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000384 mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000385
386 if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
387 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
388 }
389 mRawYuv420Image.width = TEST_IMAGE_WIDTH;
390 mRawYuv420Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000391 mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000392
393 if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) {
394 FAIL() << "Load file " << JPEG_IMAGE << " failed";
395 }
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000396 mJpegImage.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000397
Dichen Zhang761b52d2023-02-10 22:38:38 +0000398 JpegR jpegRCodec;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000399
400 jpegr_compressed_struct jpegR;
401 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
402 jpegR.data = malloc(jpegR.maxLength);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000403 ret = jpegRCodec.encodeJPEGR(
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000404 &mRawP010Image, &mRawYuv420Image, &mJpegImage, ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
405 &jpegR);
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000406 if (ret != OK) {
407 FAIL() << "Error code is " << ret;
408 }
409 if (SAVE_ENCODING_RESULT) {
410 // Output image data to file
Dichen Zhang61ede362023-02-22 18:50:13 +0000411 std::string filePath = "/sdcard/Documents/encoded_from_p010_yuv420p_jpeg_input.jpgr";
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000412 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
413 if (!imageFile.is_open()) {
414 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
415 }
416 imageFile.write((const char*)jpegR.data, jpegR.length);
417 }
418
419 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000420 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000421 decodedJpegR.data = malloc(decodedJpegRSize);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000422 ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR);
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000423 if (ret != OK) {
424 FAIL() << "Error code is " << ret;
425 }
426 if (SAVE_DECODING_RESULT) {
427 // Output image data to file
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000428 std::string filePath = "/sdcard/Documents/decoded_from_p010_yuv420p_jpeg_input.rgb";
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000429 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
430 if (!imageFile.is_open()) {
431 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
432 }
433 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
434 }
435
436 free(jpegR.data);
437 free(decodedJpegR.data);
438}
439
440/* Test Encode API-3 and decode */
Dichen Zhang761b52d2023-02-10 22:38:38 +0000441TEST_F(JpegRTest, encodeFromJpegThenDecode) {
Dichen Zhang36c1e732022-11-23 01:25:34 +0000442 int ret;
443
444 // Load input files.
445 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
446 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
447 }
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000448 mRawP010Image.width = TEST_IMAGE_WIDTH;
449 mRawP010Image.height = TEST_IMAGE_HEIGHT;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000450 mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000451
Harish Mahendrakar1e057282022-12-04 12:47:53 -0800452 if (SAVE_INPUT_RGBA) {
453 size_t rgbaSize = mRawP010Image.width * mRawP010Image.height * sizeof(uint32_t);
454 uint32_t *data = (uint32_t *)malloc(rgbaSize);
455
456 for (size_t y = 0; y < mRawP010Image.height; ++y) {
457 for (size_t x = 0; x < mRawP010Image.width; ++x) {
458 Color hdr_yuv_gamma = getP010Pixel(&mRawP010Image, x, y);
459 Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma);
460 uint32_t rgba1010102 = colorToRgba1010102(hdr_rgb_gamma);
461 size_t pixel_idx = x + y * mRawP010Image.width;
462 reinterpret_cast<uint32_t*>(data)[pixel_idx] = rgba1010102;
463 }
464 }
465
466 // Output image data to file
467 std::string filePath = "/sdcard/Documents/input_from_p010.rgb10";
468 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
469 if (!imageFile.is_open()) {
470 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
471 }
472 imageFile.write((const char*)data, rgbaSize);
473 free(data);
474 }
Dichen Zhang36c1e732022-11-23 01:25:34 +0000475 if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) {
476 FAIL() << "Load file " << JPEG_IMAGE << " failed";
477 }
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000478 mJpegImage.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000479
Dichen Zhang761b52d2023-02-10 22:38:38 +0000480 JpegR jpegRCodec;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000481
482 jpegr_compressed_struct jpegR;
Dichen Zhang7e3ed122022-12-14 22:05:01 +0000483 jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t);
Dichen Zhang36c1e732022-11-23 01:25:34 +0000484 jpegR.data = malloc(jpegR.maxLength);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000485 ret = jpegRCodec.encodeJPEGR(
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000486 &mRawP010Image, &mJpegImage, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR);
Dichen Zhang36c1e732022-11-23 01:25:34 +0000487 if (ret != OK) {
488 FAIL() << "Error code is " << ret;
489 }
490 if (SAVE_ENCODING_RESULT) {
491 // Output image data to file
Dichen Zhang61ede362023-02-22 18:50:13 +0000492 std::string filePath = "/sdcard/Documents/encoded_from_p010_jpeg_input.jpgr";
Dichen Zhang36c1e732022-11-23 01:25:34 +0000493 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
494 if (!imageFile.is_open()) {
495 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
496 }
497 imageFile.write((const char*)jpegR.data, jpegR.length);
498 }
499
500 jpegr_uncompressed_struct decodedJpegR;
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000501 int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8;
Dichen Zhang36c1e732022-11-23 01:25:34 +0000502 decodedJpegR.data = malloc(decodedJpegRSize);
Dichen Zhang761b52d2023-02-10 22:38:38 +0000503 ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR);
Dichen Zhang36c1e732022-11-23 01:25:34 +0000504 if (ret != OK) {
505 FAIL() << "Error code is " << ret;
506 }
507 if (SAVE_DECODING_RESULT) {
508 // Output image data to file
Dichen Zhang3e5798c2023-03-01 22:30:43 +0000509 std::string filePath = "/sdcard/Documents/decoded_from_p010_jpeg_input.rgb";
Dichen Zhang36c1e732022-11-23 01:25:34 +0000510 std::ofstream imageFile(filePath.c_str(), std::ofstream::binary);
511 if (!imageFile.is_open()) {
512 ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str());
513 }
514 imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize);
515 }
516
517 free(jpegR.data);
518 free(decodedJpegR.data);
519}
520
Dichen Zhang10959a42023-04-10 16:28:16 -0700521TEST_F(JpegRTest, ProfileGainMapFuncs) {
Nick Deakind19e5762023-02-10 15:39:08 -0500522 const size_t kWidth = TEST_IMAGE_WIDTH;
523 const size_t kHeight = TEST_IMAGE_HEIGHT;
524
525 // Load input files.
526 if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) {
527 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
528 }
529 mRawP010Image.width = kWidth;
530 mRawP010Image.height = kHeight;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000531 mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
Nick Deakind19e5762023-02-10 15:39:08 -0500532
533 if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) {
534 FAIL() << "Load file " << RAW_P010_IMAGE << " failed";
535 }
536 mRawYuv420Image.width = kWidth;
537 mRawYuv420Image.height = kHeight;
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000538 mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
Nick Deakind19e5762023-02-10 15:39:08 -0500539
Dichen Zhang761b52d2023-02-10 22:38:38 +0000540 JpegRBenchmark benchmark;
Nick Deakind19e5762023-02-10 15:39:08 -0500541
Nick Deakin05ceebf2023-04-19 15:27:13 -0400542 ultrahdr_metadata_struct metadata = { .version = "1.0",
Nick Deakind19e5762023-02-10 15:39:08 -0500543 .maxContentBoost = 8.0f,
544 .minContentBoost = 1.0f / 8.0f };
545
546 jpegr_uncompressed_struct map = { .data = NULL,
547 .width = 0,
548 .height = 0,
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000549 .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED };
Nick Deakind19e5762023-02-10 15:39:08 -0500550
Dichen Zhang10959a42023-04-10 16:28:16 -0700551 benchmark.BenchmarkGenerateGainMap(&mRawYuv420Image, &mRawP010Image, &metadata, &map);
Nick Deakind19e5762023-02-10 15:39:08 -0500552
553 const int dstSize = mRawYuv420Image.width * mRawYuv420Image.height * 4;
554 auto bufferDst = std::make_unique<uint8_t[]>(dstSize);
555 jpegr_uncompressed_struct dest = { .data = bufferDst.get(),
556 .width = 0,
557 .height = 0,
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000558 .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED };
Nick Deakind19e5762023-02-10 15:39:08 -0500559
Dichen Zhang10959a42023-04-10 16:28:16 -0700560 benchmark.BenchmarkApplyGainMap(&mRawYuv420Image, &map, &metadata, &dest);
Nick Deakind19e5762023-02-10 15:39:08 -0500561}
562
Dichen Zhangdbceb0e2023-04-14 19:03:18 +0000563} // namespace android::ultrahdr