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