• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 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 <fstream>
18 #include <iostream>
19 
20 #include <benchmark/benchmark.h>
21 
22 #include "ultrahdr/jpegrutils.h"
23 
24 using namespace ultrahdr;
25 
26 #ifdef __ANDROID__
27 std::string kTestImagesPath = "/sdcard/test/UltrahdrBenchmarkTestRes-1.0/";
28 #else
29 std::string kTestImagesPath = "./data/UltrahdrBenchmarkTestRes-1.0/";
30 #endif
31 
32 std::vector<std::string> kDecodeAPITestImages{
33     // 12mp test vectors
34     "mountains.jpg",
35     "mountain_lake.jpg",
36     "desert_wanda.jpg",
37     // 3mp test vectors
38     "mountains_3mp.jpg",
39     "mountain_lake_3mp.jpg",
40     "desert_wanda_3mp.jpg",
41 };
42 
43 std::vector<std::string> kEncodeApi0TestImages12MpName{
44     // 12mp test vectors
45     "mountains.p010",
46     "mountain_lake.p010",
47 };
48 
49 std::vector<std::string> kEncodeApi0TestImages3MpName{
50     // 3mp test vectors
51     "mountains_3mp.p010",
52     "mountain_lake_3mp.p010",
53 };
54 
55 std::vector<std::pair<std::string, std::string>> kEncodeApi1TestImages12MpName{
56     // 12mp test vectors
57     {"mountains.p010", "mountains.yuv"},
58     {"mountain_lake.p010", "mountain_lake.yuv"},
59 };
60 
61 std::vector<std::pair<std::string, std::string>> kEncodeApi1TestImages3MpName{
62     // 3mp test vectors
63     {"mountains_3mp.p010", "mountains_3mp.yuv"},
64     {"mountain_lake_3mp.p010", "mountain_lake_3mp.yuv"},
65 };
66 
67 std::vector<std::tuple<std::string, std::string, std::string>> kEncodeApi2TestImages12MpName{
68     // 12mp test vectors
69     {"mountains.p010", "mountains.yuv", "mountains.jpg"},
70     {"mountain_lake.p010", "mountain_lake.yuv", "mountain_lake.jpg"},
71 };
72 
73 std::vector<std::tuple<std::string, std::string, std::string>> kEncodeApi2TestImages3MpName{
74     // 3mp test vectors
75     {"mountains_3mp.p010", "mountains_3mp.yuv", "mountains_3mp.jpg"},
76     {"mountain_lake_3mp.p010", "mountain_lake_3mp.yuv", "mountain_lake_3mp.jpg"},
77 };
78 
79 std::vector<std::pair<std::string, std::string>> kEncodeApi3TestImages12MpName{
80     // 12mp test vectors
81     {"mountains.p010", "mountains.jpg"},
82     {"mountain_lake.p010", "mountain_lake.jpg"},
83 };
84 
85 std::vector<std::pair<std::string, std::string>> kEncodeApi3TestImages3MpName{
86     // 3mp test vectors
87     {"mountains_3mp.p010", "mountains_3mp.jpg"},
88     {"mountain_lake_3mp.p010", "mountain_lake_3mp.jpg"},
89 };
90 
91 std::vector<std::string> kEncodeApi4TestImages12MpName{
92     // 12mp test vectors
93     "mountains.jpg",
94     "mountain_lake.jpg",
95     "desert_wanda.jpg",
96 };
97 
98 std::vector<std::string> kEncodeApi4TestImages3MpName{
99     // 3mp test vectors
100     "mountains_3mp.jpg",
101     "mountain_lake_3mp.jpg",
102     "desert_wanda_3mp.jpg",
103 };
104 
ofToString(const ultrahdr_output_format of)105 std::string ofToString(const ultrahdr_output_format of) {
106   switch (of) {
107     case ULTRAHDR_OUTPUT_SDR:
108       return "sdr";
109     case ULTRAHDR_OUTPUT_HDR_LINEAR:
110       return "hdr linear";
111     case ULTRAHDR_OUTPUT_HDR_PQ:
112       return "hdr pq";
113     case ULTRAHDR_OUTPUT_HDR_HLG:
114       return "hdr hlg";
115     default:
116       return "Unknown";
117   }
118 }
119 
colorGamutToString(const ultrahdr_color_gamut cg)120 std::string colorGamutToString(const ultrahdr_color_gamut cg) {
121   switch (cg) {
122     case ULTRAHDR_COLORGAMUT_BT709:
123       return "bt709";
124     case ULTRAHDR_COLORGAMUT_P3:
125       return "p3";
126     case ULTRAHDR_COLORGAMUT_BT2100:
127       return "bt2100";
128     default:
129       return "Unknown";
130   }
131 }
132 
tfToString(const ultrahdr_transfer_function of)133 std::string tfToString(const ultrahdr_transfer_function of) {
134   switch (of) {
135     case ULTRAHDR_TF_LINEAR:
136       return "linear";
137     case ULTRAHDR_TF_HLG:
138       return "hlg";
139     case ULTRAHDR_TF_PQ:
140       return "pq";
141     case ULTRAHDR_TF_SRGB:
142       return "srgb";
143     default:
144       return "Unknown";
145   }
146 }
147 
loadFile(const char * filename,void * & result,int length)148 static bool loadFile(const char* filename, void*& result, int length) {
149   std::ifstream ifd(filename, std::ios::binary | std::ios::ate);
150   if (ifd.good()) {
151     int size = ifd.tellg();
152     if (size < length) {
153       std::cerr << "requested to read " << length << " bytes from file : " << filename
154                 << ", file contains only " << size << " bytes" << std::endl;
155       return false;
156     }
157     ifd.seekg(0, std::ios::beg);
158     result = new uint8_t[length];
159     if (result == nullptr) {
160       std::cerr << "failed to allocate memory to store contents of file : " << filename
161                 << std::endl;
162       return false;
163     }
164     ifd.read(static_cast<char*>(result), length);
165     return true;
166   }
167   std::cerr << "unable to open file : " << filename << std::endl;
168   return false;
169 }
170 
fillRawImageHandle(jpegr_uncompressed_struct * rawImage,int width,int height,std::string file,ultrahdr_color_gamut cg,bool isP010)171 bool fillRawImageHandle(jpegr_uncompressed_struct* rawImage, int width, int height,
172                         std::string file, ultrahdr_color_gamut cg, bool isP010) {
173   const int bpp = isP010 ? 2 : 1;
174   int imgSize = width * height * bpp * 1.5;
175   rawImage->width = width;
176   rawImage->height = height;
177   rawImage->colorGamut = cg;
178   return loadFile(file.c_str(), rawImage->data, imgSize);
179 }
180 
fillJpgImageHandle(jpegr_compressed_struct * jpgImg,std::string file,ultrahdr_color_gamut colorGamut)181 bool fillJpgImageHandle(jpegr_compressed_struct* jpgImg, std::string file,
182                         ultrahdr_color_gamut colorGamut) {
183   std::ifstream ifd(file.c_str(), std::ios::binary | std::ios::ate);
184   if (!ifd.good()) {
185     return false;
186   }
187   int size = ifd.tellg();
188   jpgImg->length = size;
189   jpgImg->maxLength = size;
190   jpgImg->data = nullptr;
191   jpgImg->colorGamut = colorGamut;
192   ifd.close();
193   return loadFile(file.c_str(), jpgImg->data, size);
194 }
195 
BM_Decode(benchmark::State & s)196 static void BM_Decode(benchmark::State& s) {
197   std::string srcFileName = kTestImagesPath + "jpegr/" + kDecodeAPITestImages[s.range(0)];
198   ultrahdr_output_format of = static_cast<ultrahdr_output_format>(s.range(1));
199 
200   std::ifstream ifd(srcFileName.c_str(), std::ios::binary | std::ios::ate);
201   if (!ifd.good()) {
202     s.SkipWithError("unable to open file " + srcFileName);
203     return;
204   }
205   int size = ifd.tellg();
206 
207   jpegr_compressed_struct jpegImgR{};
208   jpegImgR.length = size;
209   jpegImgR.maxLength = size;
210   jpegImgR.data = nullptr;
211   jpegImgR.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;
212   ifd.close();
213   if (!loadFile(srcFileName.c_str(), jpegImgR.data, size)) {
214     s.SkipWithError("unable to load file " + srcFileName);
215     return;
216   }
217 
218   std::unique_ptr<uint8_t[]> compData;
219   compData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
220 
221   JpegR jpegHdr;
222   jpegr_info_struct info{};
223   status_t status = jpegHdr.getJPEGRInfo(&jpegImgR, &info);
224   if (JPEGR_NO_ERROR != status) {
225     s.SkipWithError("getJPEGRInfo returned with error " + std::to_string(status));
226     return;
227   }
228 
229   size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4);
230   std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(outSize);
231   jpegr_uncompressed_struct destImage{};
232   destImage.data = data.get();
233   for (auto _ : s) {
234     status = jpegHdr.decodeJPEGR(&jpegImgR, &destImage, FLT_MAX, nullptr, of);
235     if (JPEGR_NO_ERROR != status) {
236       s.SkipWithError("decodeJPEGR returned with error " + std::to_string(status));
237       return;
238     }
239   }
240   if (info.width != destImage.width || info.height != destImage.height) {
241     s.SkipWithError("received unexpected width/height");
242     return;
243   }
244 
245   s.SetLabel(srcFileName + ", OutputFormat: " + ofToString(of) + ", " + std::to_string(info.width) +
246              "x" + std::to_string(info.height));
247 }
248 
BM_Encode_Api0(benchmark::State & s,std::vector<std::string> testVectors)249 static void BM_Encode_Api0(benchmark::State& s, std::vector<std::string> testVectors) {
250   int width = s.range(1);
251   int height = s.range(2);
252   ultrahdr_color_gamut p010Cg = static_cast<ultrahdr_color_gamut>(s.range(3));
253   ultrahdr_transfer_function tf = static_cast<ultrahdr_transfer_function>(s.range(4));
254 
255   s.SetLabel(testVectors[s.range(0)] + ", " + colorGamutToString(p010Cg) + ", " + tfToString(tf) +
256              ", " + std::to_string(width) + "x" + std::to_string(height));
257 
258   std::string p010File{kTestImagesPath + "p010/" + testVectors[s.range(0)]};
259 
260   jpegr_uncompressed_struct rawP010Image{};
261   if (!fillRawImageHandle(&rawP010Image, width, height, p010File, p010Cg, true)) {
262     s.SkipWithError("unable to load file : " + p010File);
263     return;
264   }
265   std::unique_ptr<uint8_t[]> rawP010ImgData;
266   rawP010ImgData.reset(reinterpret_cast<uint8_t*>(rawP010Image.data));
267 
268   jpegr_compressed_struct jpegImgR{};
269   jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
270                                   rawP010Image.width * rawP010Image.height * 3 * 2);
271   jpegImgR.data = new uint8_t[jpegImgR.maxLength];
272   if (jpegImgR.data == nullptr) {
273     s.SkipWithError("unable to allocate memory to store compressed image");
274     return;
275   }
276   std::unique_ptr<uint8_t[]> jpegImgRData;
277   jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
278 
279   JpegR jpegHdr;
280   for (auto _ : s) {
281     status_t status = jpegHdr.encodeJPEGR(&rawP010Image, tf, &jpegImgR, 95, nullptr);
282     if (JPEGR_NO_ERROR != status) {
283       s.SkipWithError("encodeJPEGR returned with error : " + std::to_string(status));
284       return;
285     }
286   }
287 }
288 
BM_Encode_Api1(benchmark::State & s,std::vector<std::pair<std::string,std::string>> testVectors)289 static void BM_Encode_Api1(benchmark::State& s,
290                            std::vector<std::pair<std::string, std::string>> testVectors) {
291   int width = s.range(1);
292   int height = s.range(2);
293   ultrahdr_color_gamut p010Cg = static_cast<ultrahdr_color_gamut>(s.range(3));
294   ultrahdr_color_gamut yuv420Cg = static_cast<ultrahdr_color_gamut>(s.range(4));
295   ultrahdr_transfer_function tf = static_cast<ultrahdr_transfer_function>(s.range(5));
296 
297   s.SetLabel(testVectors[s.range(0)].first + ", " + testVectors[s.range(0)].second + ", " +
298              "p010_" + colorGamutToString(p010Cg) + ", " + "yuv420_" +
299              colorGamutToString(yuv420Cg) + ", " + tfToString(tf) + ", " + std::to_string(width) +
300              "x" + std::to_string(height));
301 
302   std::string p010File{kTestImagesPath + "p010/" + testVectors[s.range(0)].first};
303 
304   jpegr_uncompressed_struct rawP010Image{};
305   if (!fillRawImageHandle(&rawP010Image, width, height, p010File, p010Cg, true)) {
306     s.SkipWithError("unable to load file : " + p010File);
307     return;
308   }
309   std::unique_ptr<uint8_t[]> rawP010ImgData;
310   rawP010ImgData.reset(reinterpret_cast<uint8_t*>(rawP010Image.data));
311 
312   std::string yuv420File{kTestImagesPath + "yuv420/" + testVectors[s.range(0)].second};
313 
314   jpegr_uncompressed_struct rawYuv420Image{};
315   if (!fillRawImageHandle(&rawYuv420Image, width, height, yuv420File, yuv420Cg, false)) {
316     s.SkipWithError("unable to load file : " + yuv420File);
317     return;
318   }
319   std::unique_ptr<uint8_t[]> rawYuv420ImgData;
320   rawYuv420ImgData.reset(reinterpret_cast<uint8_t*>(rawYuv420Image.data));
321 
322   jpegr_compressed_struct jpegImgR{};
323   jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
324                                   rawP010Image.width * rawP010Image.height * 3 * 2);
325   jpegImgR.data = new uint8_t[jpegImgR.maxLength];
326 
327   std::unique_ptr<uint8_t[]> jpegImgRData;
328   jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
329 
330   JpegR jpegHdr;
331   for (auto _ : s) {
332     status_t status =
333         jpegHdr.encodeJPEGR(&rawP010Image, &rawYuv420Image, tf, &jpegImgR, 95, nullptr);
334     if (JPEGR_NO_ERROR != status) {
335       s.SkipWithError("encodeJPEGR returned with error : " + std::to_string(status));
336       return;
337     }
338   }
339 }
340 
BM_Encode_Api2(benchmark::State & s,std::vector<std::tuple<std::string,std::string,std::string>> testVectors)341 static void BM_Encode_Api2(
342     benchmark::State& s,
343     std::vector<std::tuple<std::string, std::string, std::string>> testVectors) {
344   int width = s.range(1);
345   int height = s.range(2);
346   ultrahdr_color_gamut p010Cg = static_cast<ultrahdr_color_gamut>(s.range(3));
347   ultrahdr_transfer_function tf = static_cast<ultrahdr_transfer_function>(s.range(4));
348 
349   s.SetLabel(std::get<0>(testVectors[s.range(0)]) + ", " + std::get<1>(testVectors[s.range(0)]) +
350              ", " + std::get<2>(testVectors[s.range(0)]) + ", " + colorGamutToString(p010Cg) +
351              ", " + tfToString(tf) + ", " + std::to_string(width) + "x" + std::to_string(height));
352 
353   std::string p010File{kTestImagesPath + "p010/" + std::get<0>(testVectors[s.range(0)])};
354 
355   jpegr_uncompressed_struct rawP010Image{};
356   if (!fillRawImageHandle(&rawP010Image, width, height, p010File, p010Cg, true)) {
357     s.SkipWithError("unable to load file : " + p010File);
358     return;
359   }
360   std::unique_ptr<uint8_t[]> rawP010ImgData;
361   rawP010ImgData.reset(reinterpret_cast<uint8_t*>(rawP010Image.data));
362 
363   std::string yuv420File{kTestImagesPath + "yuv420/" + std::get<1>(testVectors[s.range(0)])};
364 
365   jpegr_uncompressed_struct rawYuv420Image{};
366   if (!fillRawImageHandle(&rawYuv420Image, width, height, yuv420File, ULTRAHDR_COLORGAMUT_P3,
367                           false)) {
368     s.SkipWithError("unable to load file : " + yuv420File);
369     return;
370   }
371   std::unique_ptr<uint8_t[]> rawYuv420ImgData;
372   rawYuv420ImgData.reset(reinterpret_cast<uint8_t*>(rawYuv420Image.data));
373 
374   std::string yuv420JpegFile{
375       (kTestImagesPath + "yuv420jpeg/" + std::get<2>(testVectors[s.range(0)]))};
376 
377   jpegr_compressed_struct yuv420JpegImage{};
378   if (!fillJpgImageHandle(&yuv420JpegImage, yuv420JpegFile, ULTRAHDR_COLORGAMUT_P3)) {
379     s.SkipWithError("unable to load file : " + yuv420JpegFile);
380     return;
381   }
382   std::unique_ptr<uint8_t[]> yuv420jpegImgData;
383   yuv420jpegImgData.reset(reinterpret_cast<uint8_t*>(yuv420JpegImage.data));
384 
385   jpegr_compressed_struct jpegImgR{};
386   jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
387                                   rawP010Image.width * rawP010Image.height * 3 * 2);
388   jpegImgR.data = new uint8_t[jpegImgR.maxLength];
389   if (jpegImgR.data == nullptr) {
390     s.SkipWithError("unable to allocate memory to store compressed image");
391     return;
392   }
393   std::unique_ptr<uint8_t[]> jpegImgRData;
394   jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
395 
396   JpegR jpegHdr;
397   for (auto _ : s) {
398     status_t status =
399         jpegHdr.encodeJPEGR(&rawP010Image, &rawYuv420Image, &yuv420JpegImage, tf, &jpegImgR);
400     if (JPEGR_NO_ERROR != status) {
401       s.SkipWithError("encodeJPEGR returned with error : " + std::to_string(status));
402       return;
403     }
404   }
405 }
406 
BM_Encode_Api3(benchmark::State & s,std::vector<std::pair<std::string,std::string>> testVectors)407 static void BM_Encode_Api3(benchmark::State& s,
408                            std::vector<std::pair<std::string, std::string>> testVectors) {
409   int width = s.range(1);
410   int height = s.range(2);
411   ultrahdr_color_gamut p010Cg = static_cast<ultrahdr_color_gamut>(s.range(3));
412   ultrahdr_transfer_function tf = static_cast<ultrahdr_transfer_function>(s.range(4));
413 
414   s.SetLabel(testVectors[s.range(0)].first + ", " + testVectors[s.range(0)].second + ", " +
415              colorGamutToString(p010Cg) + ", " + tfToString(tf) + ", " + std::to_string(width) +
416              "x" + std::to_string(height));
417 
418   std::string p010File{kTestImagesPath + "p010/" + testVectors[s.range(0)].first};
419 
420   jpegr_uncompressed_struct rawP010Image{};
421   if (!fillRawImageHandle(&rawP010Image, width, height, p010File, p010Cg, true)) {
422     s.SkipWithError("unable to load file : " + p010File);
423     return;
424   }
425   std::unique_ptr<uint8_t[]> rawP010ImgData;
426   rawP010ImgData.reset(reinterpret_cast<uint8_t*>(rawP010Image.data));
427 
428   std::string yuv420JpegFile{(kTestImagesPath + "yuv420jpeg/" + testVectors[s.range(0)].second)};
429 
430   jpegr_compressed_struct yuv420JpegImage{};
431   if (!fillJpgImageHandle(&yuv420JpegImage, yuv420JpegFile, ULTRAHDR_COLORGAMUT_P3)) {
432     s.SkipWithError("unable to load file : " + yuv420JpegFile);
433     return;
434   }
435   std::unique_ptr<uint8_t[]> yuv420jpegImgData;
436   yuv420jpegImgData.reset(reinterpret_cast<uint8_t*>(yuv420JpegImage.data));
437 
438   jpegr_compressed_struct jpegImgR{};
439   jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
440                                   rawP010Image.width * rawP010Image.height * 3 * 2);
441   jpegImgR.data = new uint8_t[jpegImgR.maxLength];
442   if (jpegImgR.data == nullptr) {
443     s.SkipWithError("unable to allocate memory to store compressed image");
444     return;
445   }
446   std::unique_ptr<uint8_t[]> jpegImgRData;
447   jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
448 
449   JpegR jpegHdr;
450   for (auto _ : s) {
451     status_t status = jpegHdr.encodeJPEGR(&rawP010Image, &yuv420JpegImage, tf, &jpegImgR);
452     if (JPEGR_NO_ERROR != status) {
453       s.SkipWithError("encodeJPEGR returned with error : " + std::to_string(status));
454       return;
455     }
456   }
457 }
458 
BM_Encode_Api4(benchmark::State & s)459 static void BM_Encode_Api4(benchmark::State& s) {
460   std::string srcFileName = kTestImagesPath + "jpegr/" + kDecodeAPITestImages[s.range(0)];
461 
462   std::ifstream ifd(srcFileName.c_str(), std::ios::binary | std::ios::ate);
463   if (!ifd.good()) {
464     s.SkipWithError("unable to open file " + srcFileName);
465     return;
466   }
467   int size = ifd.tellg();
468 
469   jpegr_compressed_struct inpJpegImgR{};
470   inpJpegImgR.length = size;
471   inpJpegImgR.maxLength = size;
472   inpJpegImgR.data = nullptr;
473   inpJpegImgR.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;
474   ifd.close();
475   if (!loadFile(srcFileName.c_str(), inpJpegImgR.data, size)) {
476     s.SkipWithError("unable to load file " + srcFileName);
477     return;
478   }
479   std::unique_ptr<uint8_t[]> inpJpegImgRData;
480   inpJpegImgRData.reset(reinterpret_cast<uint8_t*>(inpJpegImgR.data));
481 
482   JpegR jpegHdr;
483   jpeg_info_struct primaryImgInfo;
484   jpeg_info_struct gainmapImgInfo;
485   jpegr_info_struct info{};
486   info.primaryImgInfo = &primaryImgInfo;
487   info.gainmapImgInfo = &gainmapImgInfo;
488   status_t status = jpegHdr.getJPEGRInfo(&inpJpegImgR, &info);
489   if (JPEGR_NO_ERROR != status) {
490     s.SkipWithError("getJPEGRInfo returned with error " + std::to_string(status));
491     return;
492   }
493 
494   jpegr_compressed_struct jpegImgR{};
495   jpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */,
496                                   info.width * info.height * 3 * 2);
497   jpegImgR.data = new uint8_t[jpegImgR.maxLength];
498   if (jpegImgR.data == nullptr) {
499     s.SkipWithError("unable to allocate memory to store compressed image");
500     return;
501   }
502   std::unique_ptr<uint8_t[]> jpegImgRData;
503   jpegImgRData.reset(reinterpret_cast<uint8_t*>(jpegImgR.data));
504 
505   jpegr_compressed_struct primaryImg;
506   primaryImg.data = primaryImgInfo.imgData.data();
507   primaryImg.maxLength = primaryImg.length = primaryImgInfo.imgData.size();
508   primaryImg.colorGamut = static_cast<ultrahdr_color_gamut>(s.range(1));
509   jpegr_compressed_struct gainmapImg;
510   gainmapImg.data = gainmapImgInfo.imgData.data();
511   gainmapImg.maxLength = gainmapImg.length = gainmapImgInfo.imgData.size();
512   gainmapImg.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;
513   ultrahdr_metadata_struct uhdr_metadata;
514   if (!getMetadataFromXMP(gainmapImgInfo.xmpData.data(), gainmapImgInfo.xmpData.size(),
515                           &uhdr_metadata)) {
516     s.SkipWithError("getMetadataFromXMP returned with error");
517     return;
518   }
519   for (auto _ : s) {
520     status = jpegHdr.encodeJPEGR(&primaryImg, &gainmapImg, &uhdr_metadata, &jpegImgR);
521     if (JPEGR_NO_ERROR != status) {
522       s.SkipWithError("encodeJPEGR returned with error " + std::to_string(status));
523       return;
524     }
525   }
526 
527   s.SetLabel(srcFileName + ", " + std::to_string(info.width) + "x" + std::to_string(info.height));
528 }
529 
530 BENCHMARK(BM_Decode)
531     ->ArgsProduct({{benchmark::CreateDenseRange(0, kDecodeAPITestImages.size() - 1, 1)},
532                    {ULTRAHDR_OUTPUT_HDR_HLG, ULTRAHDR_OUTPUT_HDR_PQ, ULTRAHDR_OUTPUT_SDR}})
533     ->Unit(benchmark::kMillisecond);
534 
535 BENCHMARK_CAPTURE(BM_Encode_Api0, TestVectorName, kEncodeApi0TestImages12MpName)
536     ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi0TestImages12MpName.size() - 1, 1)},
537                    {4080},
538                    {3072},
539                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
540                    {
541                        ULTRAHDR_TF_HLG,
542                        ULTRAHDR_TF_PQ,
543                    }})
544     ->Unit(benchmark::kMillisecond);
545 
546 BENCHMARK_CAPTURE(BM_Encode_Api0, TestVectorName, kEncodeApi0TestImages3MpName)
547     ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi0TestImages3MpName.size() - 1, 1)},
548                    {2048},
549                    {1536},
550                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
551                    {
552                        ULTRAHDR_TF_HLG,
553                        ULTRAHDR_TF_PQ,
554                    }})
555     ->Unit(benchmark::kMillisecond);
556 
557 BENCHMARK_CAPTURE(BM_Encode_Api1, TestVectorName, kEncodeApi1TestImages12MpName)
558     ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi1TestImages12MpName.size() - 1, 1)},
559                    {4080},
560                    {3072},
561                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
562                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
563                    {
564                        ULTRAHDR_TF_HLG,
565                        ULTRAHDR_TF_PQ,
566                    }})
567     ->Unit(benchmark::kMillisecond);
568 
569 BENCHMARK_CAPTURE(BM_Encode_Api1, TestVectorName, kEncodeApi1TestImages3MpName)
570     ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi1TestImages3MpName.size() - 1, 1)},
571                    {2048},
572                    {1536},
573                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
574                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
575                    {
576                        ULTRAHDR_TF_HLG,
577                        ULTRAHDR_TF_PQ,
578                    }})
579     ->Unit(benchmark::kMillisecond);
580 
581 BENCHMARK_CAPTURE(BM_Encode_Api2, TestVectorName, kEncodeApi2TestImages12MpName)
582     ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi2TestImages12MpName.size() - 1, 1)},
583                    {4080},
584                    {3072},
585                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
586                    {
587                        ULTRAHDR_TF_HLG,
588                        ULTRAHDR_TF_PQ,
589                    }})
590     ->Unit(benchmark::kMillisecond);
591 
592 BENCHMARK_CAPTURE(BM_Encode_Api2, TestVectorName, kEncodeApi2TestImages3MpName)
593     ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi2TestImages3MpName.size() - 1, 1)},
594                    {2048},
595                    {1536},
596                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
597                    {
598                        ULTRAHDR_TF_HLG,
599                        ULTRAHDR_TF_PQ,
600                    }})
601     ->Unit(benchmark::kMillisecond);
602 
603 BENCHMARK_CAPTURE(BM_Encode_Api3, TestVectorName, kEncodeApi3TestImages12MpName)
604     ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi3TestImages12MpName.size() - 1, 1)},
605                    {4080},
606                    {3072},
607                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
608                    {
609                        ULTRAHDR_TF_HLG,
610                        ULTRAHDR_TF_PQ,
611                    }})
612     ->Unit(benchmark::kMillisecond);
613 
614 BENCHMARK_CAPTURE(BM_Encode_Api3, TestVectorName, kEncodeApi3TestImages3MpName)
615     ->ArgsProduct({{benchmark::CreateDenseRange(0, kEncodeApi3TestImages3MpName.size() - 1, 1)},
616                    {2048},
617                    {1536},
618                    {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
619                    {
620                        ULTRAHDR_TF_HLG,
621                        ULTRAHDR_TF_PQ,
622                    }})
623     ->Unit(benchmark::kMillisecond);
624 
625 BENCHMARK(BM_Encode_Api4)
626     ->ArgsProduct({
627         {benchmark::CreateDenseRange(0, kEncodeApi4TestImages12MpName.size() - 1, 1)},
628         {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
629     })
630     ->Unit(benchmark::kMillisecond);
631 
632 BENCHMARK(BM_Encode_Api4)
633     ->ArgsProduct({
634         {benchmark::CreateDenseRange(0, kEncodeApi4TestImages3MpName.size() - 1, 1)},
635         {ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100},
636     })
637     ->Unit(benchmark::kMillisecond);
638 
639 BENCHMARK_MAIN();
640