• 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 #ifdef _WIN32
18 #include <Windows.h>
19 #else
20 #include <sys/time.h>
21 #endif
22 
23 #include <string.h>
24 
25 #include <algorithm>
26 #include <cmath>
27 #include <cstdint>
28 #include <fstream>
29 #include <iostream>
30 #include <sstream>
31 
32 #include "ultrahdr_api.h"
33 
34 const float BT601YUVtoRGBMatrix[9] = {
35     1, 0, 1.402, 1, (-0.202008 / 0.587), (-0.419198 / 0.587), 1.0, 1.772, 0.0};
36 const float BT709YUVtoRGBMatrix[9] = {
37     1, 0, 1.5748, 1, (-0.13397432 / 0.7152), (-0.33480248 / 0.7152), 1.0, 1.8556, 0.0};
38 const float BT2020YUVtoRGBMatrix[9] = {
39     1, 0, 1.4746, 1, (-0.11156702 / 0.6780), (-0.38737742 / 0.6780), 1, 1.8814, 0};
40 
41 const float BT601RGBtoYUVMatrix[9] = {
42     0.299,           0.587, 0.114, (-0.299 / 1.772), (-0.587 / 1.772), 0.5, 0.5, (-0.587 / 1.402),
43     (-0.114 / 1.402)};
44 const float BT709RGBtoYUVMatrix[9] = {0.2126,
45                                       0.7152,
46                                       0.0722,
47                                       (-0.2126 / 1.8556),
48                                       (-0.7152 / 1.8556),
49                                       0.5,
50                                       0.5,
51                                       (-0.7152 / 1.5748),
52                                       (-0.0722 / 1.5748)};
53 const float BT2020RGBtoYUVMatrix[9] = {0.2627,
54                                        0.6780,
55                                        0.0593,
56                                        (-0.2627 / 1.8814),
57                                        (-0.6780 / 1.8814),
58                                        0.5,
59                                        0.5,
60                                        (-0.6780 / 1.4746),
61                                        (-0.0593 / 1.4746)};
62 
63 // remove these once introduced in ultrahdr_api.h
64 const int UHDR_IMG_FMT_48bppYCbCr444 = 101;
65 
66 int optind_s = 1;
67 int optopt_s = 0;
68 char* optarg_s = nullptr;
69 
getopt_s(int argc,char * const argv[],char * ostr)70 int getopt_s(int argc, char* const argv[], char* ostr) {
71   if (optind_s >= argc) return -1;
72 
73   const char* arg = argv[optind_s];
74   if (arg[0] != '-' || !arg[1]) {
75     std::cerr << "invalid option " << arg << std::endl;
76     return '?';
77   }
78   optopt_s = arg[1];
79   char* oindex = strchr(ostr, optopt_s);
80   if (!oindex) {
81     std::cerr << "unsupported option " << arg << std::endl;
82     return '?';
83   }
84   if (oindex[1] != ':') {
85     optarg_s = nullptr;
86     return optopt_s;
87   }
88 
89   if (argc > ++optind_s) {
90     optarg_s = (char*)argv[optind_s++];
91   } else {
92     std::cerr << "option " << arg << " requires an argument" << std::endl;
93     optarg_s = nullptr;
94     return '?';
95   }
96   return optopt_s;
97 }
98 
99 // #define PROFILE_ENABLE 1
100 #ifdef _WIN32
101 class Profiler {
102  public:
timerStart()103   void timerStart() { QueryPerformanceCounter(&mStartingTime); }
104 
timerStop()105   void timerStop() { QueryPerformanceCounter(&mEndingTime); }
106 
elapsedTime()107   int64_t elapsedTime() {
108     LARGE_INTEGER frequency;
109     LARGE_INTEGER elapsedMicroseconds;
110     QueryPerformanceFrequency(&frequency);
111     elapsedMicroseconds.QuadPart = mEndingTime.QuadPart - mStartingTime.QuadPart;
112     return (double)elapsedMicroseconds.QuadPart / (double)frequency.QuadPart * 1000000;
113   }
114 
115  private:
116   LARGE_INTEGER mStartingTime;
117   LARGE_INTEGER mEndingTime;
118 };
119 #else
120 class Profiler {
121  public:
timerStart()122   void timerStart() { gettimeofday(&mStartingTime, nullptr); }
123 
timerStop()124   void timerStop() { gettimeofday(&mEndingTime, nullptr); }
125 
elapsedTime()126   int64_t elapsedTime() {
127     struct timeval elapsedMicroseconds;
128     elapsedMicroseconds.tv_sec = mEndingTime.tv_sec - mStartingTime.tv_sec;
129     elapsedMicroseconds.tv_usec = mEndingTime.tv_usec - mStartingTime.tv_usec;
130     return elapsedMicroseconds.tv_sec * 1000000 + elapsedMicroseconds.tv_usec;
131   }
132 
133  private:
134   struct timeval mStartingTime;
135   struct timeval mEndingTime;
136 };
137 #endif
138 
139 #define READ_BYTES(DESC, ADDR, LEN)                                                             \
140   DESC.read(static_cast<char*>(ADDR), (LEN));                                                   \
141   if (DESC.gcount() != (LEN)) {                                                                 \
142     std::cerr << "failed to read : " << (LEN) << " bytes, read : " << DESC.gcount() << " bytes" \
143               << std::endl;                                                                     \
144     return false;                                                                               \
145   }
146 
loadFile(const char * filename,void * & result,int length)147 static bool loadFile(const char* filename, void*& result, int length) {
148   std::ifstream ifd(filename, std::ios::binary | std::ios::ate);
149   if (ifd.good()) {
150     int size = ifd.tellg();
151     if (size < length) {
152       std::cerr << "requested to read " << length << " bytes from file : " << filename
153                 << ", file contains only " << size << " bytes" << std::endl;
154       return false;
155     }
156     ifd.seekg(0, std::ios::beg);
157     result = malloc(length);
158     if (result == nullptr) {
159       std::cerr << "failed to allocate memory to store contents of file : " << filename
160                 << std::endl;
161       return false;
162     }
163     READ_BYTES(ifd, result, length)
164     return true;
165   }
166   std::cerr << "unable to open file : " << filename << std::endl;
167   return false;
168 }
169 
loadFile(const char * filename,uhdr_raw_image_t * handle)170 static bool loadFile(const char* filename, uhdr_raw_image_t* handle) {
171   std::ifstream ifd(filename, std::ios::binary);
172   if (ifd.good()) {
173     if (handle->fmt == UHDR_IMG_FMT_24bppYCbCrP010) {
174       const int bpp = 2;
175       READ_BYTES(ifd, handle->planes[UHDR_PLANE_Y], handle->w * handle->h * bpp)
176       READ_BYTES(ifd, handle->planes[UHDR_PLANE_UV], (handle->w / 2) * (handle->h / 2) * bpp * 2)
177       return true;
178     } else if (handle->fmt == UHDR_IMG_FMT_32bppRGBA1010102 ||
179                handle->fmt == UHDR_IMG_FMT_32bppRGBA8888) {
180       const int bpp = 4;
181       READ_BYTES(ifd, handle->planes[UHDR_PLANE_PACKED], handle->w * handle->h * bpp)
182       return true;
183     } else if (handle->fmt == UHDR_IMG_FMT_12bppYCbCr420) {
184       READ_BYTES(ifd, handle->planes[UHDR_PLANE_Y], handle->w * handle->h)
185       READ_BYTES(ifd, handle->planes[UHDR_PLANE_U], (handle->w / 2) * (handle->h / 2))
186       READ_BYTES(ifd, handle->planes[UHDR_PLANE_V], (handle->w / 2) * (handle->h / 2))
187       return true;
188     }
189     return false;
190   }
191   std::cerr << "unable to open file : " << filename << std::endl;
192   return false;
193 }
194 
writeFile(const char * filename,void * & result,int length)195 static bool writeFile(const char* filename, void*& result, int length) {
196   std::ofstream ofd(filename, std::ios::binary);
197   if (ofd.is_open()) {
198     ofd.write(static_cast<char*>(result), length);
199     return true;
200   }
201   std::cerr << "unable to write to file : " << filename << std::endl;
202   return false;
203 }
204 
writeFile(const char * filename,uhdr_raw_image_t * img)205 static bool writeFile(const char* filename, uhdr_raw_image_t* img) {
206   std::ofstream ofd(filename, std::ios::binary);
207   if (ofd.is_open()) {
208     if (img->fmt == UHDR_IMG_FMT_32bppRGBA8888 || img->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ||
209         img->fmt == UHDR_IMG_FMT_32bppRGBA1010102) {
210       char* data = static_cast<char*>(img->planes[UHDR_PLANE_PACKED]);
211       int bpp = img->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ? 8 : 4;
212       const size_t stride = img->stride[UHDR_PLANE_PACKED] * bpp;
213       const size_t length = img->w * bpp;
214       for (unsigned i = 0; i < img->h; i++, data += stride) {
215         ofd.write(data, length);
216       }
217       return true;
218     } else if ((int)img->fmt == UHDR_IMG_FMT_24bppYCbCr444 ||
219                (int)img->fmt == UHDR_IMG_FMT_48bppYCbCr444) {
220       char* data = static_cast<char*>(img->planes[UHDR_PLANE_Y]);
221       int bpp = (int)img->fmt == UHDR_IMG_FMT_48bppYCbCr444 ? 2 : 1;
222       size_t stride = img->stride[UHDR_PLANE_Y] * bpp;
223       size_t length = img->w * bpp;
224       for (unsigned i = 0; i < img->h; i++, data += stride) {
225         ofd.write(data, length);
226       }
227       data = static_cast<char*>(img->planes[UHDR_PLANE_U]);
228       stride = img->stride[UHDR_PLANE_U] * bpp;
229       for (unsigned i = 0; i < img->h; i++, data += stride) {
230         ofd.write(data, length);
231       }
232       data = static_cast<char*>(img->planes[UHDR_PLANE_V]);
233       stride = img->stride[UHDR_PLANE_V] * bpp;
234       for (unsigned i = 0; i < img->h; i++, data += stride) {
235         ofd.write(data, length);
236       }
237       return true;
238     }
239     return false;
240   }
241   std::cerr << "unable to write to file : " << filename << std::endl;
242   return false;
243 }
244 
245 class UltraHdrAppInput {
246  public:
UltraHdrAppInput(const char * hdrIntentRawFile,const char * sdrIntentRawFile,const char * sdrIntentCompressedFile,const char * gainmapCompressedFile,const char * gainmapMetadataCfgFile,const char * outputFile,size_t width,size_t height,uhdr_img_fmt_t hdrCf=UHDR_IMG_FMT_32bppRGBA1010102,uhdr_img_fmt_t sdrCf=UHDR_IMG_FMT_32bppRGBA8888,uhdr_color_gamut_t hdrCg=UHDR_CG_DISPLAY_P3,uhdr_color_gamut_t sdrCg=UHDR_CG_BT_709,uhdr_color_transfer_t hdrTf=UHDR_CT_HLG,int quality=95,uhdr_color_transfer_t oTf=UHDR_CT_HLG,uhdr_img_fmt_t oFmt=UHDR_IMG_FMT_32bppRGBA1010102)247   UltraHdrAppInput(const char* hdrIntentRawFile, const char* sdrIntentRawFile,
248                    const char* sdrIntentCompressedFile, const char* gainmapCompressedFile,
249                    const char* gainmapMetadataCfgFile, const char* outputFile, size_t width,
250                    size_t height, uhdr_img_fmt_t hdrCf = UHDR_IMG_FMT_32bppRGBA1010102,
251                    uhdr_img_fmt_t sdrCf = UHDR_IMG_FMT_32bppRGBA8888,
252                    uhdr_color_gamut_t hdrCg = UHDR_CG_DISPLAY_P3,
253                    uhdr_color_gamut_t sdrCg = UHDR_CG_BT_709,
254                    uhdr_color_transfer_t hdrTf = UHDR_CT_HLG, int quality = 95,
255                    uhdr_color_transfer_t oTf = UHDR_CT_HLG,
256                    uhdr_img_fmt_t oFmt = UHDR_IMG_FMT_32bppRGBA1010102)
257       : mHdrIntentRawFile(hdrIntentRawFile),
258         mSdrIntentRawFile(sdrIntentRawFile),
259         mSdrIntentCompressedFile(sdrIntentCompressedFile),
260         mGainMapCompressedFile(gainmapCompressedFile),
261         mGainMapMetadataCfgFile(gainmapMetadataCfgFile),
262         mUhdrFile(nullptr),
263         mOutputFile(outputFile),
264         mWidth(width),
265         mHeight(height),
266         mHdrCf(hdrCf),
267         mSdrCf(sdrCf),
268         mHdrCg(hdrCg),
269         mSdrCg(sdrCg),
270         mHdrTf(hdrTf),
271         mQuality(quality),
272         mOTf(oTf),
273         mOfmt(oFmt),
274         mMode(0){};
275 
UltraHdrAppInput(const char * uhdrFile,const char * outputFile,uhdr_color_transfer_t oTf=UHDR_CT_HLG,uhdr_img_fmt_t oFmt=UHDR_IMG_FMT_32bppRGBA1010102)276   UltraHdrAppInput(const char* uhdrFile, const char* outputFile,
277                    uhdr_color_transfer_t oTf = UHDR_CT_HLG,
278                    uhdr_img_fmt_t oFmt = UHDR_IMG_FMT_32bppRGBA1010102)
279       : mHdrIntentRawFile(nullptr),
280         mSdrIntentRawFile(nullptr),
281         mUhdrFile(uhdrFile),
282         mOutputFile(outputFile),
283         mWidth(0),
284         mHeight(0),
285         mHdrCf(UHDR_IMG_FMT_UNSPECIFIED),
286         mSdrCf(UHDR_IMG_FMT_UNSPECIFIED),
287         mHdrCg(UHDR_CG_UNSPECIFIED),
288         mSdrCg(UHDR_CG_UNSPECIFIED),
289         mHdrTf(UHDR_CT_UNSPECIFIED),
290         mQuality(95),
291         mOTf(oTf),
292         mOfmt(oFmt),
293         mMode(1){};
294 
~UltraHdrAppInput()295   ~UltraHdrAppInput() {
296     int count = sizeof mRawP010Image.planes / sizeof mRawP010Image.planes[UHDR_PLANE_Y];
297     for (int i = 0; i < count; i++) {
298       if (mRawP010Image.planes[i]) {
299         free(mRawP010Image.planes[i]);
300         mRawP010Image.planes[i] = nullptr;
301       }
302       if (mRawRgba1010102Image.planes[i]) {
303         free(mRawRgba1010102Image.planes[i]);
304         mRawRgba1010102Image.planes[i] = nullptr;
305       }
306       if (mRawYuv420Image.planes[i]) {
307         free(mRawYuv420Image.planes[i]);
308         mRawYuv420Image.planes[i] = nullptr;
309       }
310       if (mRawRgba8888Image.planes[i]) {
311         free(mRawRgba8888Image.planes[i]);
312         mRawRgba8888Image.planes[i] = nullptr;
313       }
314       if (mDecodedUhdrRgbImage.planes[i]) {
315         free(mDecodedUhdrRgbImage.planes[i]);
316         mDecodedUhdrRgbImage.planes[i] = nullptr;
317       }
318       if (mDecodedUhdrYuv444Image.planes[i]) {
319         free(mDecodedUhdrYuv444Image.planes[i]);
320         mDecodedUhdrYuv444Image.planes[i] = nullptr;
321       }
322     }
323     if (mUhdrImage.data) free(mUhdrImage.data);
324   }
325 
326   bool fillUhdrImageHandle();
327   bool fillP010ImageHandle();
328   bool fillRGBA1010102ImageHandle();
329   bool convertP010ToRGBImage();
330   bool fillYuv420ImageHandle();
331   bool fillRGBA8888ImageHandle();
332   bool convertYuv420ToRGBImage();
333   bool fillSdrCompressedImageHandle();
334   bool fillGainMapCompressedImageHandle();
335   bool fillGainMapMetadataDescriptor();
336   bool convertRgba8888ToYUV444Image();
337   bool convertRgba1010102ToYUV444Image();
338   bool encode();
339   bool decode();
340   void computeRGBHdrPSNR();
341   void computeRGBSdrPSNR();
342   void computeYUVHdrPSNR();
343   void computeYUVSdrPSNR();
344 
345   const char* mHdrIntentRawFile;
346   const char* mSdrIntentRawFile;
347   const char* mSdrIntentCompressedFile;
348   const char* mGainMapCompressedFile;
349   const char* mGainMapMetadataCfgFile;
350   const char* mUhdrFile;
351   const char* mOutputFile;
352   const int mWidth;
353   const int mHeight;
354   const uhdr_img_fmt_t mHdrCf;
355   const uhdr_img_fmt_t mSdrCf;
356   const uhdr_color_gamut_t mHdrCg;
357   const uhdr_color_gamut_t mSdrCg;
358   const uhdr_color_transfer_t mHdrTf;
359   const int mQuality;
360   const uhdr_color_transfer_t mOTf;
361   const uhdr_img_fmt_t mOfmt;
362   const int mMode;
363 
364   uhdr_raw_image_t mRawP010Image{};
365   uhdr_raw_image_t mRawRgba1010102Image{};
366   uhdr_raw_image_t mRawYuv420Image{};
367   uhdr_raw_image_t mRawRgba8888Image{};
368   uhdr_compressed_image_t mSdrIntentCompressedImage{};
369   uhdr_compressed_image_t mGainMapCompressedImage{};
370   uhdr_gainmap_metadata mGainMapMetadata{};
371   uhdr_compressed_image_t mUhdrImage{};
372   uhdr_raw_image_t mDecodedUhdrRgbImage{};
373   uhdr_raw_image_t mDecodedUhdrYuv444Image{};
374   double mPsnr[3]{};
375 };
376 
fillP010ImageHandle()377 bool UltraHdrAppInput::fillP010ImageHandle() {
378   const int bpp = 2;
379   int p010Size = mWidth * mHeight * bpp * 1.5;
380   mRawP010Image.fmt = UHDR_IMG_FMT_24bppYCbCrP010;
381   mRawP010Image.cg = mHdrCg;
382   mRawP010Image.ct = mHdrTf;
383   mRawP010Image.range = UHDR_CR_LIMITED_RANGE;
384   mRawP010Image.w = mWidth;
385   mRawP010Image.h = mHeight;
386   mRawP010Image.planes[UHDR_PLANE_Y] = malloc(mWidth * mHeight * bpp);
387   mRawP010Image.planes[UHDR_PLANE_UV] = malloc((mWidth / 2) * (mHeight / 2) * bpp * 2);
388   mRawP010Image.planes[UHDR_PLANE_V] = nullptr;
389   mRawP010Image.stride[UHDR_PLANE_Y] = mWidth;
390   mRawP010Image.stride[UHDR_PLANE_UV] = mWidth;
391   mRawP010Image.stride[UHDR_PLANE_V] = 0;
392   return loadFile(mHdrIntentRawFile, &mRawP010Image);
393 }
394 
fillYuv420ImageHandle()395 bool UltraHdrAppInput::fillYuv420ImageHandle() {
396   int yuv420Size = mWidth * mHeight * 1.5;
397   mRawYuv420Image.fmt = UHDR_IMG_FMT_12bppYCbCr420;
398   mRawYuv420Image.cg = mSdrCg;
399   mRawYuv420Image.ct = UHDR_CT_SRGB;
400   mRawYuv420Image.range = UHDR_CR_FULL_RANGE;
401   mRawYuv420Image.w = mWidth;
402   mRawYuv420Image.h = mHeight;
403   mRawYuv420Image.planes[UHDR_PLANE_Y] = malloc(mWidth * mHeight);
404   mRawYuv420Image.planes[UHDR_PLANE_U] = malloc((mWidth / 2) * (mHeight / 2));
405   mRawYuv420Image.planes[UHDR_PLANE_V] = malloc((mWidth / 2) * (mHeight / 2));
406   mRawYuv420Image.stride[UHDR_PLANE_Y] = mWidth;
407   mRawYuv420Image.stride[UHDR_PLANE_U] = mWidth / 2;
408   mRawYuv420Image.stride[UHDR_PLANE_V] = mWidth / 2;
409   return loadFile(mSdrIntentRawFile, &mRawYuv420Image);
410 }
411 
fillRGBA1010102ImageHandle()412 bool UltraHdrAppInput::fillRGBA1010102ImageHandle() {
413   const int bpp = 4;
414   mRawRgba1010102Image.fmt = UHDR_IMG_FMT_32bppRGBA1010102;
415   mRawRgba1010102Image.cg = mHdrCg;
416   mRawRgba1010102Image.ct = mHdrTf;
417   mRawRgba1010102Image.range = UHDR_CR_FULL_RANGE;
418   mRawRgba1010102Image.w = mWidth;
419   mRawRgba1010102Image.h = mHeight;
420   mRawRgba1010102Image.planes[UHDR_PLANE_PACKED] = malloc(mWidth * mHeight * bpp);
421   mRawRgba1010102Image.planes[UHDR_PLANE_UV] = nullptr;
422   mRawRgba1010102Image.planes[UHDR_PLANE_V] = nullptr;
423   mRawRgba1010102Image.stride[UHDR_PLANE_PACKED] = mWidth;
424   mRawRgba1010102Image.stride[UHDR_PLANE_UV] = 0;
425   mRawRgba1010102Image.stride[UHDR_PLANE_V] = 0;
426   return loadFile(mHdrIntentRawFile, &mRawRgba1010102Image);
427 }
428 
fillRGBA8888ImageHandle()429 bool UltraHdrAppInput::fillRGBA8888ImageHandle() {
430   const int bpp = 4;
431   mRawRgba8888Image.fmt = UHDR_IMG_FMT_32bppRGBA8888;
432   mRawRgba8888Image.cg = mSdrCg;
433   mRawRgba8888Image.ct = UHDR_CT_SRGB;
434   mRawRgba8888Image.range = UHDR_CR_FULL_RANGE;
435   mRawRgba8888Image.w = mWidth;
436   mRawRgba8888Image.h = mHeight;
437   mRawRgba8888Image.planes[UHDR_PLANE_PACKED] = malloc(mWidth * mHeight * bpp);
438   mRawRgba8888Image.planes[UHDR_PLANE_U] = nullptr;
439   mRawRgba8888Image.planes[UHDR_PLANE_V] = nullptr;
440   mRawRgba8888Image.stride[UHDR_PLANE_Y] = mWidth;
441   mRawRgba8888Image.stride[UHDR_PLANE_U] = 0;
442   mRawRgba8888Image.stride[UHDR_PLANE_V] = 0;
443   return loadFile(mSdrIntentRawFile, &mRawRgba8888Image);
444 }
445 
fillSdrCompressedImageHandle()446 bool UltraHdrAppInput::fillSdrCompressedImageHandle() {
447   std::ifstream ifd(mSdrIntentCompressedFile, std::ios::binary | std::ios::ate);
448   if (ifd.good()) {
449     int size = ifd.tellg();
450     mSdrIntentCompressedImage.capacity = size;
451     mSdrIntentCompressedImage.data_sz = size;
452     mSdrIntentCompressedImage.data = nullptr;
453     mSdrIntentCompressedImage.cg = mSdrCg;
454     mSdrIntentCompressedImage.ct = UHDR_CT_UNSPECIFIED;
455     mSdrIntentCompressedImage.range = UHDR_CR_UNSPECIFIED;
456     ifd.close();
457     return loadFile(mSdrIntentCompressedFile, mSdrIntentCompressedImage.data, size);
458   }
459   return false;
460 }
461 
fillGainMapCompressedImageHandle()462 bool UltraHdrAppInput::fillGainMapCompressedImageHandle() {
463   std::ifstream ifd(mGainMapCompressedFile, std::ios::binary | std::ios::ate);
464   if (ifd.good()) {
465     int size = ifd.tellg();
466     mGainMapCompressedImage.capacity = size;
467     mGainMapCompressedImage.data_sz = size;
468     mGainMapCompressedImage.data = nullptr;
469     mGainMapCompressedImage.cg = UHDR_CG_UNSPECIFIED;
470     mGainMapCompressedImage.ct = UHDR_CT_UNSPECIFIED;
471     mGainMapCompressedImage.range = UHDR_CR_UNSPECIFIED;
472     ifd.close();
473     return loadFile(mGainMapCompressedFile, mGainMapCompressedImage.data, size);
474   }
475   return false;
476 }
477 
parse_argument(uhdr_gainmap_metadata * metadata,char * argument,float * value)478 void parse_argument(uhdr_gainmap_metadata* metadata, char* argument, float* value) {
479   if (!strcmp(argument, "maxContentBoost"))
480     metadata->max_content_boost = *value;
481   else if (!strcmp(argument, "minContentBoost"))
482     metadata->min_content_boost = *value;
483   else if (!strcmp(argument, "gamma"))
484     metadata->gamma = *value;
485   else if (!strcmp(argument, "offsetSdr"))
486     metadata->offset_sdr = *value;
487   else if (!strcmp(argument, "offsetHdr"))
488     metadata->offset_hdr = *value;
489   else if (!strcmp(argument, "hdrCapacityMin"))
490     metadata->hdr_capacity_min = *value;
491   else if (!strcmp(argument, "hdrCapacityMax"))
492     metadata->hdr_capacity_max = *value;
493   else
494     std::cout << " Ignoring argument " << argument << std::endl;
495 }
496 
fillGainMapMetadataDescriptor()497 bool UltraHdrAppInput::fillGainMapMetadataDescriptor() {
498   std::ifstream file(mGainMapMetadataCfgFile);
499   if (!file.is_open()) {
500     return false;
501   }
502   std::string line;
503   char argument[128];
504   float value;
505   while (std::getline(file, line)) {
506     if (sscanf(line.c_str(), "--%s %f", argument, &value) == 2) {
507       parse_argument(&mGainMapMetadata, argument, &value);
508     }
509   }
510   file.close();
511   return true;
512 }
513 
fillUhdrImageHandle()514 bool UltraHdrAppInput::fillUhdrImageHandle() {
515   std::ifstream ifd(mUhdrFile, std::ios::binary | std::ios::ate);
516   if (ifd.good()) {
517     int size = ifd.tellg();
518     mUhdrImage.capacity = size;
519     mUhdrImage.data_sz = size;
520     mUhdrImage.data = nullptr;
521     mUhdrImage.cg = UHDR_CG_UNSPECIFIED;
522     mUhdrImage.ct = UHDR_CT_UNSPECIFIED;
523     mUhdrImage.range = UHDR_CR_UNSPECIFIED;
524     ifd.close();
525     return loadFile(mUhdrFile, mUhdrImage.data, size);
526   }
527   return false;
528 }
529 
encode()530 bool UltraHdrAppInput::encode() {
531   if (mHdrIntentRawFile != nullptr) {
532     if (mHdrCf == UHDR_IMG_FMT_24bppYCbCrP010) {
533       if (!fillP010ImageHandle()) {
534         std::cerr << " failed to load file " << mHdrIntentRawFile << std::endl;
535         return false;
536       }
537     } else if (mHdrCf == UHDR_IMG_FMT_32bppRGBA1010102) {
538       if (!fillRGBA1010102ImageHandle()) {
539         std::cerr << " failed to load file " << mHdrIntentRawFile << std::endl;
540         return false;
541       }
542     } else {
543       std::cerr << " invalid hdr intent color format " << mHdrCf << std::endl;
544       return false;
545     }
546   }
547   if (mSdrIntentRawFile != nullptr) {
548     if (mSdrCf == UHDR_IMG_FMT_12bppYCbCr420) {
549       if (!fillYuv420ImageHandle()) {
550         std::cerr << " failed to load file " << mSdrIntentRawFile << std::endl;
551         return false;
552       }
553     } else if (mSdrCf == UHDR_IMG_FMT_32bppRGBA8888) {
554       if (!fillRGBA8888ImageHandle()) {
555         std::cerr << " failed to load file " << mSdrIntentRawFile << std::endl;
556         return false;
557       }
558     } else {
559       std::cerr << " invalid sdr intent color format " << mSdrCf << std::endl;
560       return false;
561     }
562   }
563   if (mSdrIntentCompressedFile != nullptr) {
564     if (!fillSdrCompressedImageHandle()) {
565       std::cerr << " failed to load file " << mSdrIntentCompressedFile << std::endl;
566       return false;
567     }
568   }
569   if (mGainMapCompressedFile != nullptr && mGainMapMetadataCfgFile != nullptr) {
570     if (!fillGainMapCompressedImageHandle()) {
571       std::cerr << " failed to load file " << mGainMapCompressedFile << std::endl;
572       return false;
573     }
574     if (!fillGainMapMetadataDescriptor()) {
575       std::cerr << " failed to read config file " << mGainMapMetadataCfgFile << std::endl;
576       return false;
577     }
578   }
579 
580 #define RET_IF_ERR(x)                            \
581   {                                              \
582     uhdr_error_info_t status = (x);              \
583     if (status.error_code != UHDR_CODEC_OK) {    \
584       if (status.has_detail) {                   \
585         std::cerr << status.detail << std::endl; \
586       }                                          \
587       uhdr_release_encoder(handle);              \
588       return false;                              \
589     }                                            \
590   }
591   uhdr_codec_private_t* handle = uhdr_create_encoder();
592   if (mHdrIntentRawFile != nullptr) {
593     if (mHdrCf == UHDR_IMG_FMT_24bppYCbCrP010) {
594       RET_IF_ERR(uhdr_enc_set_raw_image(handle, &mRawP010Image, UHDR_HDR_IMG))
595     } else if (mHdrCf == UHDR_IMG_FMT_32bppRGBA1010102) {
596       RET_IF_ERR(uhdr_enc_set_raw_image(handle, &mRawRgba1010102Image, UHDR_HDR_IMG))
597     }
598   }
599   if (mSdrIntentRawFile != nullptr) {
600     if (mSdrCf == UHDR_IMG_FMT_12bppYCbCr420) {
601       RET_IF_ERR(uhdr_enc_set_raw_image(handle, &mRawYuv420Image, UHDR_SDR_IMG))
602     } else if (mSdrCf == UHDR_IMG_FMT_32bppRGBA8888) {
603       RET_IF_ERR(uhdr_enc_set_raw_image(handle, &mRawRgba8888Image, UHDR_SDR_IMG))
604     }
605   }
606   if (mSdrIntentCompressedFile != nullptr) {
607     RET_IF_ERR(uhdr_enc_set_compressed_image(
608         handle, &mSdrIntentCompressedImage,
609         (mGainMapCompressedFile != nullptr && mGainMapMetadataCfgFile != nullptr) ? UHDR_BASE_IMG
610                                                                                   : UHDR_SDR_IMG))
611   }
612   if (mGainMapCompressedFile != nullptr && mGainMapMetadataCfgFile != nullptr) {
613     RET_IF_ERR(uhdr_enc_set_gainmap_image(handle, &mGainMapCompressedImage, &mGainMapMetadata))
614   }
615   RET_IF_ERR(uhdr_enc_set_quality(handle, mQuality, UHDR_BASE_IMG))
616 #ifdef PROFILE_ENABLE
617   const int profileCount = 10;
618   Profiler profileEncode;
619   profileEncode.timerStart();
620   for (auto i = 0; i < profileCount; i++) {
621 #endif
622     RET_IF_ERR(uhdr_encode(handle))
623 #ifdef PROFILE_ENABLE
624   }
625   profileEncode.timerStop();
626   auto avgEncTime = profileEncode.elapsedTime() / (profileCount * 1000.f);
627   printf("Average encode time for res %d x %d is %f ms \n", mWidth, mHeight, avgEncTime);
628 #endif
629 
630 #undef RET_IF_ERR
631 
632   auto output = uhdr_get_encoded_stream(handle);
633 
634   // for decoding
635   mUhdrImage.data = malloc(output->data_sz);
636   memcpy(mUhdrImage.data, output->data, output->data_sz);
637   mUhdrImage.capacity = mUhdrImage.data_sz = output->data_sz;
638   mUhdrImage.cg = output->cg;
639   mUhdrImage.ct = output->ct;
640   mUhdrImage.range = output->range;
641   writeFile(mOutputFile, output->data, output->data_sz);
642   uhdr_release_encoder(handle);
643 
644   return true;
645 }
646 
decode()647 bool UltraHdrAppInput::decode() {
648   if (mMode == 1 && !fillUhdrImageHandle()) {
649     std::cerr << " failed to load file " << mUhdrFile << std::endl;
650     return false;
651   }
652 
653 #define RET_IF_ERR(x)                            \
654   {                                              \
655     uhdr_error_info_t status = (x);              \
656     if (status.error_code != UHDR_CODEC_OK) {    \
657       if (status.has_detail) {                   \
658         std::cerr << status.detail << std::endl; \
659       }                                          \
660       uhdr_release_decoder(handle);              \
661       return false;                              \
662     }                                            \
663   }
664 
665   uhdr_codec_private_t* handle = uhdr_create_decoder();
666   RET_IF_ERR(uhdr_dec_set_image(handle, &mUhdrImage))
667   RET_IF_ERR(uhdr_dec_set_out_color_transfer(handle, mOTf))
668   RET_IF_ERR(uhdr_dec_set_out_img_format(handle, mOfmt))
669 
670 #ifdef PROFILE_ENABLE
671   const int profileCount = 10;
672   Profiler profileDecode;
673   profileDecode.timerStart();
674   for (auto i = 0; i < profileCount; i++) {
675 #endif
676     RET_IF_ERR(uhdr_decode(handle))
677 #ifdef PROFILE_ENABLE
678   }
679   profileDecode.timerStop();
680   auto avgDecTime = profileDecode.elapsedTime() / (profileCount * 1000.f);
681   printf("Average decode time for res %ld x %ld is %f ms \n", info.width, info.height, avgDecTime);
682 #endif
683 
684 #undef RET_IF_ERR
685 
686   uhdr_raw_image_t* output = uhdr_get_decoded_image(handle);
687 
688   mDecodedUhdrRgbImage.fmt = output->fmt;
689   mDecodedUhdrRgbImage.cg = output->cg;
690   mDecodedUhdrRgbImage.ct = output->ct;
691   mDecodedUhdrRgbImage.range = output->range;
692   mDecodedUhdrRgbImage.w = output->w;
693   mDecodedUhdrRgbImage.h = output->h;
694   int bpp = (output->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) ? 8 : 4;
695   mDecodedUhdrRgbImage.planes[UHDR_PLANE_PACKED] = malloc(output->w * output->h * bpp);
696   char* inData = static_cast<char*>(output->planes[UHDR_PLANE_PACKED]);
697   char* outData = static_cast<char*>(mDecodedUhdrRgbImage.planes[UHDR_PLANE_PACKED]);
698   const size_t inStride = output->stride[UHDR_PLANE_PACKED] * bpp;
699   const size_t outStride = output->w * bpp;
700   mDecodedUhdrRgbImage.stride[UHDR_PLANE_PACKED] = output->w;
701   const size_t length = output->w * bpp;
702   for (unsigned i = 0; i < output->h; i++, inData += inStride, outData += outStride) {
703     memcpy(outData, inData, length);
704   }
705   writeFile(mOutputFile, output);
706   uhdr_release_decoder(handle);
707 
708   return true;
709 }
710 
711 #define CLIP3(x, min, max) ((x) < (min)) ? (min) : ((x) > (max)) ? (max) : (x)
convertP010ToRGBImage()712 bool UltraHdrAppInput::convertP010ToRGBImage() {
713   const float* coeffs = BT2020YUVtoRGBMatrix;
714   if (mHdrCg == UHDR_CG_BT_709) {
715     coeffs = BT709YUVtoRGBMatrix;
716   } else if (mHdrCg == UHDR_CG_BT_2100) {
717     coeffs = BT2020YUVtoRGBMatrix;
718   } else if (mHdrCg == UHDR_CG_DISPLAY_P3) {
719     coeffs = BT601YUVtoRGBMatrix;
720   } else {
721     std::cerr << "color matrix not present for gamut " << mHdrCg << " using BT2020Matrix"
722               << std::endl;
723   }
724 
725   mRawRgba1010102Image.fmt = UHDR_IMG_FMT_32bppRGBA1010102;
726   mRawRgba1010102Image.cg = mRawP010Image.cg;
727   mRawRgba1010102Image.ct = mRawP010Image.ct;
728   mRawRgba1010102Image.range = UHDR_CR_FULL_RANGE;
729   mRawRgba1010102Image.w = mRawP010Image.w;
730   mRawRgba1010102Image.h = mRawP010Image.h;
731   mRawRgba1010102Image.planes[UHDR_PLANE_PACKED] = malloc(mRawP010Image.w * mRawP010Image.h * 4);
732   mRawRgba1010102Image.planes[UHDR_PLANE_U] = nullptr;
733   mRawRgba1010102Image.planes[UHDR_PLANE_V] = nullptr;
734   mRawRgba1010102Image.stride[UHDR_PLANE_PACKED] = mWidth;
735   mRawRgba1010102Image.stride[UHDR_PLANE_U] = 0;
736   mRawRgba1010102Image.stride[UHDR_PLANE_V] = 0;
737 
738   uint32_t* rgbData = static_cast<uint32_t*>(mRawRgba1010102Image.planes[UHDR_PLANE_PACKED]);
739   uint16_t* y = static_cast<uint16_t*>(mRawP010Image.planes[UHDR_PLANE_Y]);
740   uint16_t* u = static_cast<uint16_t*>(mRawP010Image.planes[UHDR_PLANE_UV]);
741   uint16_t* v = u + 1;
742 
743   for (size_t i = 0; i < mRawP010Image.h; i++) {
744     for (size_t j = 0; j < mRawP010Image.w; j++) {
745       float y0 = float(y[mRawP010Image.stride[UHDR_PLANE_Y] * i + j] >> 6);
746       float u0 = float(u[mRawP010Image.stride[UHDR_PLANE_UV] * (i / 2) + (j / 2) * 2] >> 6);
747       float v0 = float(v[mRawP010Image.stride[UHDR_PLANE_UV] * (i / 2) + (j / 2) * 2] >> 6);
748 
749       y0 = CLIP3(y0, 64.0f, 940.0f);
750       u0 = CLIP3(u0, 64.0f, 960.0f);
751       v0 = CLIP3(v0, 64.0f, 960.0f);
752 
753       y0 = (y0 - 64.0f) / 876.0f;
754       u0 = (u0 - 512.0f) / 896.0f;
755       v0 = (v0 - 512.0f) / 896.0f;
756 
757       float r = coeffs[0] * y0 + coeffs[1] * u0 + coeffs[2] * v0;
758       float g = coeffs[3] * y0 + coeffs[4] * u0 + coeffs[5] * v0;
759       float b = coeffs[6] * y0 + coeffs[7] * u0 + coeffs[8] * v0;
760 
761       r = CLIP3(r * 1023.0f + 0.5f, 0.0f, 1023.0f);
762       g = CLIP3(g * 1023.0f + 0.5f, 0.0f, 1023.0f);
763       b = CLIP3(b * 1023.0f + 0.5f, 0.0f, 1023.0f);
764 
765       int32_t r0 = int32_t(r);
766       int32_t g0 = int32_t(g);
767       int32_t b0 = int32_t(b);
768       *rgbData = (0x3ff & r0) | ((0x3ff & g0) << 10) | ((0x3ff & b0) << 20) |
769                  (0x3 << 30);  // Set alpha to 1.0
770 
771       rgbData++;
772     }
773   }
774 #ifdef DUMP_DEBUG_DATA
775   writeFile("inRgba1010102.raw", &mRawRgba1010102Image);
776 #endif
777   return true;
778 }
779 
convertYuv420ToRGBImage()780 bool UltraHdrAppInput::convertYuv420ToRGBImage() {
781   mRawRgba8888Image.fmt = UHDR_IMG_FMT_32bppRGBA8888;
782   mRawRgba8888Image.cg = mRawYuv420Image.cg;
783   mRawRgba8888Image.ct = mRawYuv420Image.ct;
784   mRawRgba8888Image.range = UHDR_CR_FULL_RANGE;
785   mRawRgba8888Image.w = mRawYuv420Image.w;
786   mRawRgba8888Image.h = mRawYuv420Image.h;
787   mRawRgba8888Image.planes[UHDR_PLANE_PACKED] = malloc(mRawYuv420Image.w * mRawYuv420Image.h * 4);
788   mRawRgba8888Image.planes[UHDR_PLANE_U] = nullptr;
789   mRawRgba8888Image.planes[UHDR_PLANE_V] = nullptr;
790   mRawRgba8888Image.stride[UHDR_PLANE_PACKED] = mWidth;
791   mRawRgba8888Image.stride[UHDR_PLANE_U] = 0;
792   mRawRgba8888Image.stride[UHDR_PLANE_V] = 0;
793 
794   uint32_t* rgbData = static_cast<uint32_t*>(mRawRgba8888Image.planes[UHDR_PLANE_PACKED]);
795   uint8_t* y = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_Y]);
796   uint8_t* u = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_U]);
797   uint8_t* v = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_V]);
798 
799   const float* coeffs = BT601YUVtoRGBMatrix;
800   if (mSdrCg == UHDR_CG_BT_709) {
801     coeffs = BT709YUVtoRGBMatrix;
802   } else if (mSdrCg == UHDR_CG_BT_2100) {
803     coeffs = BT2020YUVtoRGBMatrix;
804   } else if (mSdrCg == UHDR_CG_DISPLAY_P3) {
805     coeffs = BT601YUVtoRGBMatrix;
806   } else {
807     std::cerr << "color matrix not present for gamut " << mSdrCg << " using BT601Matrix"
808               << std::endl;
809   }
810   for (size_t i = 0; i < mRawYuv420Image.h; i++) {
811     for (size_t j = 0; j < mRawYuv420Image.w; j++) {
812       float y0 = float(y[mRawYuv420Image.stride[UHDR_PLANE_Y] * i + j]);
813       float u0 = float(u[mRawYuv420Image.stride[UHDR_PLANE_U] * (i / 2) + (j / 2)] - 128);
814       float v0 = float(v[mRawYuv420Image.stride[UHDR_PLANE_V] * (i / 2) + (j / 2)] - 128);
815 
816       y0 /= 255.0f;
817       u0 /= 255.0f;
818       v0 /= 255.0f;
819 
820       float r = coeffs[0] * y0 + coeffs[1] * u0 + coeffs[2] * v0;
821       float g = coeffs[3] * y0 + coeffs[4] * u0 + coeffs[5] * v0;
822       float b = coeffs[6] * y0 + coeffs[7] * u0 + coeffs[8] * v0;
823 
824       r = r * 255.0f + 0.5f;
825       g = g * 255.0f + 0.5f;
826       b = b * 255.0f + 0.5f;
827 
828       r = CLIP3(r, 0.0f, 255.0f);
829       g = CLIP3(g, 0.0f, 255.0f);
830       b = CLIP3(b, 0.0f, 255.0f);
831 
832       int32_t r0 = int32_t(r);
833       int32_t g0 = int32_t(g);
834       int32_t b0 = int32_t(b);
835       *rgbData = r0 | (g0 << 8) | (b0 << 16) | (255 << 24);  // Set alpha to 1.0
836 
837       rgbData++;
838     }
839   }
840 #ifdef DUMP_DEBUG_DATA
841   writeFile("inRgba8888.raw", &mRawRgba8888Image);
842 #endif
843   return true;
844 }
845 
convertRgba8888ToYUV444Image()846 bool UltraHdrAppInput::convertRgba8888ToYUV444Image() {
847   mDecodedUhdrYuv444Image.fmt = static_cast<uhdr_img_fmt_t>(UHDR_IMG_FMT_24bppYCbCr444);
848   mDecodedUhdrYuv444Image.cg = mDecodedUhdrRgbImage.cg;
849   mDecodedUhdrYuv444Image.ct = mDecodedUhdrRgbImage.ct;
850   mDecodedUhdrYuv444Image.range = UHDR_CR_FULL_RANGE;
851   mDecodedUhdrYuv444Image.w = mDecodedUhdrRgbImage.w;
852   mDecodedUhdrYuv444Image.h = mDecodedUhdrRgbImage.h;
853   mDecodedUhdrYuv444Image.planes[UHDR_PLANE_Y] =
854       malloc(mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h);
855   mDecodedUhdrYuv444Image.planes[UHDR_PLANE_U] =
856       malloc(mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h);
857   mDecodedUhdrYuv444Image.planes[UHDR_PLANE_V] =
858       malloc(mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h);
859   mDecodedUhdrYuv444Image.stride[UHDR_PLANE_Y] = mWidth;
860   mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] = mWidth;
861   mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] = mWidth;
862 
863   uint32_t* rgbData = static_cast<uint32_t*>(mDecodedUhdrRgbImage.planes[UHDR_PLANE_PACKED]);
864 
865   uint8_t* yData = static_cast<uint8_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_Y]);
866   uint8_t* uData = static_cast<uint8_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_U]);
867   uint8_t* vData = static_cast<uint8_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_V]);
868 
869   const float* coeffs = BT601RGBtoYUVMatrix;
870   if (mDecodedUhdrRgbImage.cg == UHDR_CG_BT_709) {
871     coeffs = BT709RGBtoYUVMatrix;
872   } else if (mDecodedUhdrRgbImage.cg == UHDR_CG_BT_2100) {
873     coeffs = BT2020RGBtoYUVMatrix;
874   } else if (mDecodedUhdrRgbImage.cg == UHDR_CG_DISPLAY_P3) {
875     coeffs = BT601RGBtoYUVMatrix;
876   } else {
877     std::cerr << "color matrix not present for gamut " << mDecodedUhdrRgbImage.cg
878               << " using BT601Matrix" << std::endl;
879   }
880 
881   for (size_t i = 0; i < mDecodedUhdrRgbImage.h; i++) {
882     for (size_t j = 0; j < mDecodedUhdrRgbImage.w; j++) {
883       float r0 = float(rgbData[mDecodedUhdrRgbImage.stride[UHDR_PLANE_PACKED] * i + j] & 0xff);
884       float g0 =
885           float((rgbData[mDecodedUhdrRgbImage.stride[UHDR_PLANE_PACKED] * i + j] >> 8) & 0xff);
886       float b0 =
887           float((rgbData[mDecodedUhdrRgbImage.stride[UHDR_PLANE_PACKED] * i + j] >> 16) & 0xff);
888 
889       r0 /= 255.0f;
890       g0 /= 255.0f;
891       b0 /= 255.0f;
892 
893       float y = coeffs[0] * r0 + coeffs[1] * g0 + coeffs[2] * b0;
894       float u = coeffs[3] * r0 + coeffs[4] * g0 + coeffs[5] * b0;
895       float v = coeffs[6] * r0 + coeffs[7] * g0 + coeffs[8] * b0;
896 
897       y = y * 255.0f + 0.5f;
898       u = u * 255.0f + 0.5f + 128.0f;
899       v = v * 255.0f + 0.5f + 128.0f;
900 
901       y = CLIP3(y, 0.0f, 255.0f);
902       u = CLIP3(u, 0.0f, 255.0f);
903       v = CLIP3(v, 0.0f, 255.0f);
904 
905       yData[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_Y] * i + j] = uint8_t(y);
906       uData[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * i + j] = uint8_t(u);
907       vData[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * i + j] = uint8_t(v);
908     }
909   }
910 #ifdef DUMP_DEBUG_DATA
911   writeFile("outyuv444.yuv", &mDecodedUhdrYuv444Image);
912 #endif
913   return true;
914 }
915 
convertRgba1010102ToYUV444Image()916 bool UltraHdrAppInput::convertRgba1010102ToYUV444Image() {
917   const float* coeffs = BT2020RGBtoYUVMatrix;
918   if (mDecodedUhdrRgbImage.cg == UHDR_CG_BT_709) {
919     coeffs = BT709RGBtoYUVMatrix;
920   } else if (mDecodedUhdrRgbImage.cg == UHDR_CG_BT_2100) {
921     coeffs = BT2020RGBtoYUVMatrix;
922   } else if (mDecodedUhdrRgbImage.cg == UHDR_CG_DISPLAY_P3) {
923     coeffs = BT601RGBtoYUVMatrix;
924   } else {
925     std::cerr << "color matrix not present for gamut " << mDecodedUhdrRgbImage.cg
926               << " using BT2020Matrix" << std::endl;
927   }
928 
929   mDecodedUhdrYuv444Image.fmt = static_cast<uhdr_img_fmt_t>(UHDR_IMG_FMT_48bppYCbCr444);
930   mDecodedUhdrYuv444Image.cg = mDecodedUhdrRgbImage.cg;
931   mDecodedUhdrYuv444Image.ct = mDecodedUhdrRgbImage.ct;
932   mDecodedUhdrYuv444Image.range = UHDR_CR_LIMITED_RANGE;
933   mDecodedUhdrYuv444Image.w = mDecodedUhdrRgbImage.w;
934   mDecodedUhdrYuv444Image.h = mDecodedUhdrRgbImage.h;
935   mDecodedUhdrYuv444Image.planes[UHDR_PLANE_Y] =
936       malloc(mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h * 2);
937   mDecodedUhdrYuv444Image.planes[UHDR_PLANE_U] =
938       malloc(mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h * 2);
939   mDecodedUhdrYuv444Image.planes[UHDR_PLANE_V] =
940       malloc(mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h * 2);
941   mDecodedUhdrYuv444Image.stride[UHDR_PLANE_Y] = mWidth;
942   mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] = mWidth;
943   mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] = mWidth;
944 
945   uint32_t* rgbData = static_cast<uint32_t*>(mDecodedUhdrRgbImage.planes[UHDR_PLANE_PACKED]);
946 
947   uint16_t* yData = static_cast<uint16_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_Y]);
948   uint16_t* uData = static_cast<uint16_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_U]);
949   uint16_t* vData = static_cast<uint16_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_V]);
950 
951   for (size_t i = 0; i < mDecodedUhdrRgbImage.h; i++) {
952     for (size_t j = 0; j < mDecodedUhdrRgbImage.w; j++) {
953       float r0 = float(rgbData[mDecodedUhdrRgbImage.stride[UHDR_PLANE_PACKED] * i + j] & 0x3ff);
954       float g0 =
955           float((rgbData[mDecodedUhdrRgbImage.stride[UHDR_PLANE_PACKED] * i + j] >> 10) & 0x3ff);
956       float b0 =
957           float((rgbData[mDecodedUhdrRgbImage.stride[UHDR_PLANE_PACKED] * i + j] >> 20) & 0x3ff);
958 
959       r0 /= 1023.0f;
960       g0 /= 1023.0f;
961       b0 /= 1023.0f;
962 
963       float y = coeffs[0] * r0 + coeffs[1] * g0 + coeffs[2] * b0;
964       float u = coeffs[3] * r0 + coeffs[4] * g0 + coeffs[5] * b0;
965       float v = coeffs[6] * r0 + coeffs[7] * g0 + coeffs[8] * b0;
966 
967       y = (y * 876.0f) + 64.0f + 0.5f;
968       u = (u * 896.0f) + 512.0f + 0.5f;
969       v = (v * 896.0f) + 512.0f + 0.5f;
970 
971       y = CLIP3(y, 64.0f, 940.0f);
972       u = CLIP3(u, 64.0f, 960.0f);
973       v = CLIP3(v, 64.0f, 960.0f);
974 
975       yData[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_Y] * i + j] = uint16_t(y);
976       uData[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * i + j] = uint16_t(u);
977       vData[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * i + j] = uint16_t(v);
978     }
979   }
980 #ifdef DUMP_DEBUG_DATA
981   writeFile("outyuv444.yuv", &mDecodedUhdrYuv444Image);
982 #endif
983   return true;
984 }
985 
computeRGBHdrPSNR()986 void UltraHdrAppInput::computeRGBHdrPSNR() {
987   if (mOfmt != UHDR_IMG_FMT_32bppRGBA1010102) {
988     std::cout << "psnr not supported for output format " << mOfmt << std::endl;
989     return;
990   }
991   uint32_t* rgbDataSrc = static_cast<uint32_t*>(mRawRgba1010102Image.planes[UHDR_PLANE_PACKED]);
992   uint32_t* rgbDataDst = static_cast<uint32_t*>(mDecodedUhdrRgbImage.planes[UHDR_PLANE_PACKED]);
993   if (rgbDataSrc == nullptr || rgbDataDst == nullptr) {
994     std::cerr << "invalid src or dst pointer for psnr computation " << std::endl;
995     return;
996   }
997   if (mOTf != mHdrTf) {
998     std::cout << "input transfer function and output format are not compatible, psnr results "
999                  "may be unreliable"
1000               << std::endl;
1001   }
1002   uint64_t rSqError = 0, gSqError = 0, bSqError = 0;
1003   for (size_t i = 0; i < mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h; i++) {
1004     int rSrc = *rgbDataSrc & 0x3ff;
1005     int rDst = *rgbDataDst & 0x3ff;
1006     rSqError += (rSrc - rDst) * (rSrc - rDst);
1007 
1008     int gSrc = (*rgbDataSrc >> 10) & 0x3ff;
1009     int gDst = (*rgbDataDst >> 10) & 0x3ff;
1010     gSqError += (gSrc - gDst) * (gSrc - gDst);
1011 
1012     int bSrc = (*rgbDataSrc >> 20) & 0x3ff;
1013     int bDst = (*rgbDataDst >> 20) & 0x3ff;
1014     bSqError += (bSrc - bDst) * (bSrc - bDst);
1015 
1016     rgbDataSrc++;
1017     rgbDataDst++;
1018   }
1019   double meanSquareError = (double)rSqError / (mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h);
1020   mPsnr[0] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100;
1021 
1022   meanSquareError = (double)gSqError / (mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h);
1023   mPsnr[1] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100;
1024 
1025   meanSquareError = (double)bSqError / (mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h);
1026   mPsnr[2] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100;
1027 
1028   std::cout << "psnr r :: " << mPsnr[0] << " psnr g :: " << mPsnr[1] << " psnr b :: " << mPsnr[2]
1029             << std::endl;
1030 }
1031 
computeRGBSdrPSNR()1032 void UltraHdrAppInput::computeRGBSdrPSNR() {
1033   if (mOfmt != UHDR_IMG_FMT_32bppRGBA8888) {
1034     std::cout << "psnr not supported for output format " << mOfmt << std::endl;
1035     return;
1036   }
1037   uint32_t* rgbDataSrc = static_cast<uint32_t*>(mRawRgba8888Image.planes[UHDR_PLANE_PACKED]);
1038   uint32_t* rgbDataDst = static_cast<uint32_t*>(mDecodedUhdrRgbImage.planes[UHDR_PLANE_PACKED]);
1039   if (rgbDataSrc == nullptr || rgbDataDst == nullptr) {
1040     std::cerr << "invalid src or dst pointer for psnr computation " << std::endl;
1041     return;
1042   }
1043 
1044   uint64_t rSqError = 0, gSqError = 0, bSqError = 0;
1045   for (size_t i = 0; i < mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h; i++) {
1046     int rSrc = *rgbDataSrc & 0xff;
1047     int rDst = *rgbDataDst & 0xff;
1048     rSqError += (rSrc - rDst) * (rSrc - rDst);
1049 
1050     int gSrc = (*rgbDataSrc >> 8) & 0xff;
1051     int gDst = (*rgbDataDst >> 8) & 0xff;
1052     gSqError += (gSrc - gDst) * (gSrc - gDst);
1053 
1054     int bSrc = (*rgbDataSrc >> 16) & 0xff;
1055     int bDst = (*rgbDataDst >> 16) & 0xff;
1056     bSqError += (bSrc - bDst) * (bSrc - bDst);
1057 
1058     rgbDataSrc++;
1059     rgbDataDst++;
1060   }
1061   double meanSquareError = (double)rSqError / (mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h);
1062   mPsnr[0] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100;
1063 
1064   meanSquareError = (double)gSqError / (mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h);
1065   mPsnr[1] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100;
1066 
1067   meanSquareError = (double)bSqError / (mDecodedUhdrRgbImage.w * mDecodedUhdrRgbImage.h);
1068   mPsnr[2] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100;
1069 
1070   std::cout << "psnr r :: " << mPsnr[0] << " psnr g :: " << mPsnr[1] << " psnr b :: " << mPsnr[2]
1071             << std::endl;
1072 }
1073 
computeYUVHdrPSNR()1074 void UltraHdrAppInput::computeYUVHdrPSNR() {
1075   if (mOfmt != UHDR_IMG_FMT_32bppRGBA1010102) {
1076     std::cout << "psnr not supported for output format " << mOfmt << std::endl;
1077     return;
1078   }
1079   uint16_t* yDataSrc = static_cast<uint16_t*>(mRawP010Image.planes[UHDR_PLANE_Y]);
1080   uint16_t* uDataSrc = static_cast<uint16_t*>(mRawP010Image.planes[UHDR_PLANE_UV]);
1081   uint16_t* vDataSrc = uDataSrc + 1;
1082 
1083   uint16_t* yDataDst = static_cast<uint16_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_Y]);
1084   uint16_t* uDataDst = static_cast<uint16_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_U]);
1085   uint16_t* vDataDst = static_cast<uint16_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_V]);
1086   if (yDataSrc == nullptr || uDataSrc == nullptr || yDataDst == nullptr || uDataDst == nullptr ||
1087       vDataDst == nullptr) {
1088     std::cerr << "invalid src or dst pointer for psnr computation " << std::endl;
1089     return;
1090   }
1091   if (mOTf != mHdrTf) {
1092     std::cout << "input transfer function and output format are not compatible, psnr results "
1093                  "may be unreliable"
1094               << std::endl;
1095   }
1096 
1097   uint64_t ySqError = 0, uSqError = 0, vSqError = 0;
1098   for (size_t i = 0; i < mDecodedUhdrYuv444Image.h; i++) {
1099     for (size_t j = 0; j < mDecodedUhdrYuv444Image.w; j++) {
1100       int ySrc = (yDataSrc[mRawP010Image.stride[UHDR_PLANE_Y] * i + j] >> 6) & 0x3ff;
1101       ySrc = CLIP3(ySrc, 64, 940);
1102       int yDst = yDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_Y] * i + j] & 0x3ff;
1103       ySqError += (ySrc - yDst) * (ySrc - yDst);
1104 
1105       if (i % 2 == 0 && j % 2 == 0) {
1106         int uSrc =
1107             (uDataSrc[mRawP010Image.stride[UHDR_PLANE_UV] * (i / 2) + (j / 2) * 2] >> 6) & 0x3ff;
1108         uSrc = CLIP3(uSrc, 64, 960);
1109         int uDst = uDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * i + j] & 0x3ff;
1110         uDst += uDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * i + j + 1] & 0x3ff;
1111         uDst += uDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * (i + 1) + j + 1] & 0x3ff;
1112         uDst += uDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * (i + 1) + j + 1] & 0x3ff;
1113         uDst = (uDst + 2) >> 2;
1114         uSqError += (uSrc - uDst) * (uSrc - uDst);
1115 
1116         int vSrc =
1117             (vDataSrc[mRawP010Image.stride[UHDR_PLANE_UV] * (i / 2) + (j / 2) * 2] >> 6) & 0x3ff;
1118         vSrc = CLIP3(vSrc, 64, 960);
1119         int vDst = vDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * i + j] & 0x3ff;
1120         vDst += vDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * i + j + 1] & 0x3ff;
1121         vDst += vDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * (i + 1) + j + 1] & 0x3ff;
1122         vDst += vDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * (i + 1) + j + 1] & 0x3ff;
1123         vDst = (vDst + 2) >> 2;
1124         vSqError += (vSrc - vDst) * (vSrc - vDst);
1125       }
1126     }
1127   }
1128 
1129   double meanSquareError =
1130       (double)ySqError / (mDecodedUhdrYuv444Image.w * mDecodedUhdrYuv444Image.h);
1131   mPsnr[0] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100;
1132 
1133   meanSquareError = (double)uSqError / (mDecodedUhdrYuv444Image.w * mDecodedUhdrYuv444Image.h / 4);
1134   mPsnr[1] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100;
1135 
1136   meanSquareError = (double)vSqError / (mDecodedUhdrYuv444Image.w * mDecodedUhdrYuv444Image.h / 4);
1137   mPsnr[2] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100;
1138 
1139   std::cout << "psnr y :: " << mPsnr[0] << " psnr u :: " << mPsnr[1] << " psnr v :: " << mPsnr[2]
1140             << std::endl;
1141 }
1142 
computeYUVSdrPSNR()1143 void UltraHdrAppInput::computeYUVSdrPSNR() {
1144   if (mOfmt != UHDR_IMG_FMT_32bppRGBA8888) {
1145     std::cout << "psnr not supported for output format " << mOfmt << std::endl;
1146     return;
1147   }
1148 
1149   uint8_t* yDataSrc = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_Y]);
1150   uint8_t* uDataSrc = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_U]);
1151   uint8_t* vDataSrc = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_V]);
1152 
1153   uint8_t* yDataDst = static_cast<uint8_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_Y]);
1154   uint8_t* uDataDst = static_cast<uint8_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_U]);
1155   uint8_t* vDataDst = static_cast<uint8_t*>(mDecodedUhdrYuv444Image.planes[UHDR_PLANE_V]);
1156 
1157   uint64_t ySqError = 0, uSqError = 0, vSqError = 0;
1158   for (size_t i = 0; i < mDecodedUhdrYuv444Image.h; i++) {
1159     for (size_t j = 0; j < mDecodedUhdrYuv444Image.w; j++) {
1160       int ySrc = yDataSrc[mRawYuv420Image.stride[UHDR_PLANE_Y] * i + j];
1161       int yDst = yDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_Y] * i + j];
1162       ySqError += (ySrc - yDst) * (ySrc - yDst);
1163 
1164       if (i % 2 == 0 && j % 2 == 0) {
1165         int uSrc = uDataSrc[mRawYuv420Image.stride[UHDR_PLANE_U] * (i / 2) + j / 2];
1166         int uDst = uDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * i + j];
1167         uDst += uDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * i + j + 1];
1168         uDst += uDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * (i + 1) + j];
1169         uDst += uDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_U] * (i + 1) + j + 1];
1170         uDst = (uDst + 2) >> 2;
1171         uSqError += (uSrc - uDst) * (uSrc - uDst);
1172 
1173         int vSrc = vDataSrc[mRawYuv420Image.stride[UHDR_PLANE_V] * (i / 2) + j / 2];
1174         int vDst = vDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * i + j];
1175         vDst += vDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * i + j + 1];
1176         vDst += vDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * (i + 1) + j];
1177         vDst += vDataDst[mDecodedUhdrYuv444Image.stride[UHDR_PLANE_V] * (i + 1) + j + 1];
1178         vDst = (vDst + 2) >> 2;
1179         vSqError += (vSrc - vDst) * (vSrc - vDst);
1180       }
1181     }
1182   }
1183   double meanSquareError =
1184       (double)ySqError / (mDecodedUhdrYuv444Image.w * mDecodedUhdrYuv444Image.h);
1185   mPsnr[0] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100;
1186 
1187   meanSquareError = (double)uSqError / (mDecodedUhdrYuv444Image.w * mDecodedUhdrYuv444Image.h / 4);
1188   mPsnr[1] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100;
1189 
1190   meanSquareError = (double)vSqError / (mDecodedUhdrYuv444Image.w * mDecodedUhdrYuv444Image.h / 4);
1191   mPsnr[2] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100;
1192 
1193   std::cout << "psnr y :: " << mPsnr[0] << " psnr u :: " << mPsnr[1] << " psnr v :: " << mPsnr[2]
1194             << std::endl;
1195 }
1196 
usage(const char * name)1197 static void usage(const char* name) {
1198   fprintf(stderr, "\n## ultra hdr demo application.\nUsage : %s \n", name);
1199   fprintf(stderr, "    -m    mode of operation. [0:encode, 1:decode] \n");
1200   fprintf(stderr, "\n## encoder options : \n");
1201   fprintf(stderr,
1202           "    -p    raw 10 bit input resource, required for encoding scenarios 0, 1, 2, 3. \n");
1203   fprintf(stderr, "    -y    raw 8 bit input resource, required for encoding scenarios 1, 2. \n");
1204   fprintf(stderr,
1205           "    -a    raw 10 bit input resource color format, optional. [0:p010, 5:rgba1010102 "
1206           "(default)] \n");
1207   fprintf(stderr,
1208           "    -b    raw 8 bit input resource color format, optional. [1:yuv420, 3:rgba8888 "
1209           "(default)] \n");
1210   fprintf(stderr,
1211           "    -i    compressed 8 bit jpeg file path, required for encoding scenarios 2, 3, 4. \n");
1212   fprintf(stderr,
1213           "    -g    compressed 8 bit gainmap file path, required for encoding scenario 4. \n");
1214   fprintf(stderr, "    -f    gainmap metadata config file, required for encoding scenario 4. \n");
1215   fprintf(stderr, "    -w    input file width. \n");
1216   fprintf(stderr, "    -h    input file height. \n");
1217   fprintf(stderr,
1218           "    -C    10 bit input color gamut, optional. [0:bt709, 1:p3 (default), 2:bt2100] \n");
1219   fprintf(stderr,
1220           "    -c    8 bit input color gamut, optional. [0:bt709 (default), 1:p3, 2:bt2100] \n");
1221   fprintf(
1222       stderr,
1223       "    -t    10 bit input transfer function, optional. [0:linear, 1:hlg (default), 2:pq] \n");
1224   fprintf(stderr,
1225           "    -q    quality factor to be used while encoding 8 bit image, optional. [0-100], 95 : "
1226           "default.\n"
1227           "          gain map image does not use this quality factor. \n"
1228           "          for now gain map image quality factor is not configurable. \n");
1229   fprintf(stderr, "    -e    compute psnr, optional. [0:no (default), 1:yes] \n");
1230   fprintf(stderr, "\n## decoder options : \n");
1231   fprintf(stderr, "    -j    ultra hdr compressed input resource. \n");
1232   fprintf(
1233       stderr,
1234       "    -o    output transfer function, optional. [0:linear, 1:hlg (default), 2:pq, 3:srgb] \n");
1235   fprintf(
1236       stderr,
1237       "    -O    output color format, optional. [3:rgba8888, 4:rgbahalffloat, 5:rgba1010102 "
1238       "(default)] \n"
1239       "          It should be noted that not all combinations of output color format and output \n"
1240       "          transfer function are supported. \n"
1241       "          srgb output color transfer shall be paired with rgba8888 only. \n"
1242       "          hlg, pq shall be paired with rgba1010102. \n"
1243       "          linear shall be paired with rgbahalffloat. \n");
1244   fprintf(stderr, "\n## common options : \n");
1245   fprintf(stderr,
1246           "    -z    output filename, optional. \n"
1247           "          in encoding mode, default output filename 'out.jpeg'. \n"
1248           "          in decoding mode, default output filename 'outrgb.raw'. \n");
1249   fprintf(stderr, "\n## examples of usage :\n");
1250   fprintf(stderr, "\n## encode scenario 0 :\n");
1251   fprintf(stderr,
1252           "    ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -w 1920 -h 1080 -q 97 -a 0\n");
1253   fprintf(stderr,
1254           "    ultrahdr_app -m 0 -p cosmat_1920x1080_rgba1010102.raw -w 1920 -h 1080 -q 97 -a 5\n");
1255   fprintf(
1256       stderr,
1257       "    ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -w 1920 -h 1080 -q 97 -C 1 -t 2 -a 0\n");
1258   fprintf(stderr,
1259           "    ultrahdr_app -m 0 -p cosmat_1920x1080_rgba1010102.raw -w 1920 -h 1080 -q 97 -C 1 "
1260           "-t 2 -a 5\n");
1261   fprintf(stderr, "\n## encode scenario 1 :\n");
1262   fprintf(stderr,
1263           "    ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 "
1264           "-h 1080 -q 97 -a 0 -b 1\n");
1265   fprintf(stderr,
1266           "    ultrahdr_app -m 0 -p cosmat_1920x1080_rgba1010102.raw "
1267           "-y cosmat_1920x1080_rgba8888.raw -w 1920 -h 1080 -q 97 -a 5 -b 3\n");
1268   fprintf(stderr,
1269           "    ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 "
1270           "-h 1080 -q 97 -C 2 -c 1 -t 1 -a 0 -b 1\n");
1271   fprintf(stderr,
1272           "    ultrahdr_app -m 0 -p cosmat_1920x1080_rgba1010102.raw "
1273           "-y cosmat_1920x1080_rgba8888.raw -w 1920 -h 1080 -q 97 -C 2 -c 1 -t 1 -a 5 -b 3\n");
1274   fprintf(stderr,
1275           "    ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 "
1276           "-h 1080 -q 97 -C 2 -c 1 -t 1 -e 1 -a 0 -b 1\n");
1277   fprintf(stderr, "\n## encode scenario 2 :\n");
1278   fprintf(stderr,
1279           "    ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -i "
1280           "cosmat_1920x1080_420_8bit.jpg -w 1920 -h 1080 -t 1 -o 3 -O 3 -e 1 -a 0 -b 1\n");
1281   fprintf(stderr,
1282           "    ultrahdr_app -m 0 -p cosmat_1920x1080_rgba1010102.raw -y cosmat_1920x1080_420.yuv "
1283           "-i cosmat_1920x1080_420_8bit.jpg -w 1920 -h 1080 -t 1 -o 3 -O 3 -e 1 -a 5 -b 1\n");
1284   fprintf(stderr, "\n## encode scenario 3 :\n");
1285   fprintf(stderr,
1286           "    ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -i cosmat_1920x1080_420_8bit.jpg -w "
1287           "1920 -h 1080 -t 1 -o 1 -O 5 -e 1 -a 0\n");
1288   fprintf(stderr,
1289           "    ultrahdr_app -m 0 -p cosmat_1920x1080_rgba1010102.raw "
1290           "-i cosmat_1920x1080_420_8bit.jpg -w 1920 -h 1080 -t 1 -o 1 -O 5 -e 1 -a 5\n");
1291   fprintf(stderr, "\n## encode scenario 4 :\n");
1292   fprintf(stderr,
1293           "    ultrahdr_app -m 0 -i cosmat_1920x1080_420_8bit.jpg -g cosmat_1920x1080_420_8bit.jpg "
1294           "-f metadata.cfg\n");
1295   fprintf(stderr, "\n## decode api :\n");
1296   fprintf(stderr, "    ultrahdr_app -m 1 -j cosmat_1920x1080_hdr.jpg \n");
1297   fprintf(stderr, "    ultrahdr_app -m 1 -j cosmat_1920x1080_hdr.jpg -o 3 -O 3\n");
1298   fprintf(stderr, "    ultrahdr_app -m 1 -j cosmat_1920x1080_hdr.jpg -o 1 -O 5\n");
1299   fprintf(stderr, "\n");
1300 }
1301 
main(int argc,char * argv[])1302 int main(int argc, char* argv[]) {
1303   char opt_string[] = "p:y:i:g:f:w:h:C:c:t:q:o:O:m:j:e:a:b:z:";
1304   char *hdr_intent_raw_file = nullptr, *sdr_intent_raw_file = nullptr, *uhdr_file = nullptr,
1305        *sdr_intent_compressed_file = nullptr, *gainmap_compressed_file = nullptr,
1306        *gainmap_metadata_cfg_file = nullptr, *output_file = nullptr;
1307   int width = 0, height = 0;
1308   uhdr_color_gamut_t hdr_cg = UHDR_CG_DISPLAY_P3;
1309   uhdr_color_gamut_t sdr_cg = UHDR_CG_BT_709;
1310   uhdr_img_fmt_t hdr_cf = UHDR_IMG_FMT_32bppRGBA1010102;
1311   uhdr_img_fmt_t sdr_cf = UHDR_IMG_FMT_32bppRGBA8888;
1312   uhdr_color_transfer_t hdr_tf = UHDR_CT_HLG;
1313   int quality = 95;
1314   uhdr_color_transfer_t out_tf = UHDR_CT_HLG;
1315   uhdr_img_fmt_t out_cf = UHDR_IMG_FMT_32bppRGBA1010102;
1316   int mode = -1;
1317   int compute_psnr = 0;
1318   int ch;
1319   while ((ch = getopt_s(argc, argv, opt_string)) != -1) {
1320     switch (ch) {
1321       case 'a':
1322         hdr_cf = static_cast<uhdr_img_fmt_t>(atoi(optarg_s));
1323         break;
1324       case 'b':
1325         sdr_cf = static_cast<uhdr_img_fmt_t>(atoi(optarg_s));
1326         break;
1327       case 'p':
1328         hdr_intent_raw_file = optarg_s;
1329         break;
1330       case 'y':
1331         sdr_intent_raw_file = optarg_s;
1332         break;
1333       case 'i':
1334         sdr_intent_compressed_file = optarg_s;
1335         break;
1336       case 'g':
1337         gainmap_compressed_file = optarg_s;
1338         break;
1339       case 'f':
1340         gainmap_metadata_cfg_file = optarg_s;
1341         break;
1342       case 'w':
1343         width = atoi(optarg_s);
1344         break;
1345       case 'h':
1346         height = atoi(optarg_s);
1347         break;
1348       case 'C':
1349         hdr_cg = static_cast<uhdr_color_gamut_t>(atoi(optarg_s));
1350         break;
1351       case 'c':
1352         sdr_cg = static_cast<uhdr_color_gamut_t>(atoi(optarg_s));
1353         break;
1354       case 't':
1355         hdr_tf = static_cast<uhdr_color_transfer_t>(atoi(optarg_s));
1356         break;
1357       case 'q':
1358         quality = atoi(optarg_s);
1359         break;
1360       case 'O':
1361         out_cf = static_cast<uhdr_img_fmt_t>(atoi(optarg_s));
1362         break;
1363       case 'o':
1364         out_tf = static_cast<uhdr_color_transfer_t>(atoi(optarg_s));
1365         break;
1366       case 'm':
1367         mode = atoi(optarg_s);
1368         break;
1369       case 'j':
1370         uhdr_file = optarg_s;
1371         break;
1372       case 'e':
1373         compute_psnr = atoi(optarg_s);
1374         break;
1375       case 'z':
1376         output_file = optarg_s;
1377         break;
1378       default:
1379         usage(argv[0]);
1380         return -1;
1381     }
1382   }
1383   if (mode == 0) {
1384     if (width <= 0) {
1385       std::cerr << "did not receive valid image width for encoding. width :  " << width
1386                 << std::endl;
1387       return -1;
1388     }
1389     if (height <= 0) {
1390       std::cerr << "did not receive valid image height for encoding. height :  " << height
1391                 << std::endl;
1392       return -1;
1393     }
1394     if (hdr_intent_raw_file == nullptr &&
1395         (sdr_intent_compressed_file == nullptr || gainmap_compressed_file == nullptr ||
1396          gainmap_metadata_cfg_file == nullptr)) {
1397       std::cerr << "did not receive raw resources for encoding." << std::endl;
1398       return -1;
1399     }
1400     UltraHdrAppInput appInput(hdr_intent_raw_file, sdr_intent_raw_file, sdr_intent_compressed_file,
1401                               gainmap_compressed_file, gainmap_metadata_cfg_file,
1402                               output_file ? output_file : "out.jpeg", width, height, hdr_cf, sdr_cf,
1403                               hdr_cg, sdr_cg, hdr_tf, quality, out_tf, out_cf);
1404     if (!appInput.encode()) return -1;
1405     if (compute_psnr == 1) {
1406       if (!appInput.decode()) return -1;
1407       if (out_cf == UHDR_IMG_FMT_32bppRGBA8888 && sdr_intent_raw_file != nullptr) {
1408         if (sdr_cf == UHDR_IMG_FMT_12bppYCbCr420) {
1409           appInput.convertYuv420ToRGBImage();
1410         }
1411         appInput.computeRGBSdrPSNR();
1412         if (sdr_cf == UHDR_IMG_FMT_12bppYCbCr420) {
1413           appInput.convertRgba8888ToYUV444Image();
1414           appInput.computeYUVSdrPSNR();
1415         }
1416       } else if (out_cf == UHDR_IMG_FMT_32bppRGBA1010102 && hdr_intent_raw_file != nullptr) {
1417         if (hdr_cf == UHDR_IMG_FMT_24bppYCbCrP010) {
1418           appInput.convertP010ToRGBImage();
1419         }
1420         appInput.computeRGBHdrPSNR();
1421         if (hdr_cf == UHDR_IMG_FMT_24bppYCbCrP010) {
1422           appInput.convertRgba1010102ToYUV444Image();
1423           appInput.computeYUVHdrPSNR();
1424         }
1425       } else {
1426         std::cerr << "failed to compute psnr " << std::endl;
1427       }
1428     }
1429   } else if (mode == 1) {
1430     if (uhdr_file == nullptr) {
1431       std::cerr << "did not receive resources for decoding " << std::endl;
1432       return -1;
1433     }
1434     UltraHdrAppInput appInput(uhdr_file, output_file ? output_file : "outrgb.raw", out_tf, out_cf);
1435     if (!appInput.decode()) return -1;
1436   } else {
1437     std::cerr << "unrecognized input mode " << mode << std::endl;
1438     usage(argv[0]);
1439     return -1;
1440   }
1441 
1442   return 0;
1443 }
1444