diff options
Diffstat (limited to 'examples/ultrahdr_app.cpp')
-rw-r--r-- | examples/ultrahdr_app.cpp | 902 |
1 files changed, 573 insertions, 329 deletions
diff --git a/examples/ultrahdr_app.cpp b/examples/ultrahdr_app.cpp index 20b9329..cc87d5b 100644 --- a/examples/ultrahdr_app.cpp +++ b/examples/ultrahdr_app.cpp @@ -24,14 +24,12 @@ #include <algorithm> #include <cmath> +#include <cstdint> #include <fstream> #include <iostream> +#include <sstream> -#include "ultrahdr/ultrahdrcommon.h" -#include "ultrahdr/gainmapmath.h" -#include "ultrahdr/jpegr.h" - -using namespace ultrahdr; +#include "ultrahdr_api.h" const float BT601YUVtoRGBMatrix[9] = { 1, 0, 1.402, 1, (-0.202008 / 0.587), (-0.419198 / 0.587), 1.0, 1.772, 0.0}; @@ -62,6 +60,10 @@ const float BT2020RGBtoYUVMatrix[9] = {0.2627, (-0.6780 / 1.4746), (-0.0593 / 1.4746)}; +// remove these once introduced in ultrahdr_api.h +const int UHDR_IMG_FMT_24bppYCbCr444 = 100; +const int UHDR_IMG_FMT_48bppYCbCr444 = 101; + int optind_s = 1; int optopt_s = 0; char* optarg_s = nullptr; @@ -158,6 +160,27 @@ static bool loadFile(const char* filename, void*& result, int length) { return false; } +static bool loadFile(const char* filename, uhdr_raw_image_t* handle) { + std::ifstream ifd(filename, std::ios::binary); + if (ifd.good()) { + if (handle->fmt == UHDR_IMG_FMT_24bppYCbCrP010) { + const int bpp = 2; + ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_Y]), handle->w * handle->h * bpp); + ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_UV]), + (handle->w / 2) * (handle->h / 2) * bpp * 2); + return true; + } else if (handle->fmt == UHDR_IMG_FMT_12bppYCbCr420) { + ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_Y]), handle->w * handle->h); + ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_U]), (handle->w / 2) * (handle->h / 2)); + ifd.read(static_cast<char*>(handle->planes[UHDR_PLANE_V]), (handle->w / 2) * (handle->h / 2)); + return true; + } + return false; + } + std::cerr << "unable to open file : " << filename << std::endl; + return false; +} + static bool writeFile(const char* filename, void*& result, int length) { std::ofstream ofd(filename, std::ios::binary); if (ofd.is_open()) { @@ -168,54 +191,115 @@ static bool writeFile(const char* filename, void*& result, int length) { return false; } +static bool writeFile(const char* filename, uhdr_raw_image_t* img) { + std::ofstream ofd(filename, std::ios::binary); + if (ofd.is_open()) { + if (img->fmt == UHDR_IMG_FMT_32bppRGBA8888 || img->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat || + img->fmt == UHDR_IMG_FMT_32bppRGBA1010102) { + char* data = static_cast<char*>(img->planes[UHDR_PLANE_PACKED]); + int bpp = img->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ? 8 : 4; + const size_t stride = img->stride[UHDR_PLANE_PACKED] * bpp; + const size_t length = img->w * bpp; + for (unsigned i = 0; i < img->h; i++, data += stride) { + ofd.write(data, length); + } + return true; + } else if ((int)img->fmt == UHDR_IMG_FMT_24bppYCbCr444 || + (int)img->fmt == UHDR_IMG_FMT_48bppYCbCr444) { + char* data = static_cast<char*>(img->planes[UHDR_PLANE_Y]); + int bpp = (int)img->fmt == UHDR_IMG_FMT_48bppYCbCr444 ? 2 : 1; + size_t stride = img->stride[UHDR_PLANE_Y] * bpp; + size_t length = img->w * bpp; + for (unsigned i = 0; i < img->h; i++, data += stride) { + ofd.write(data, length); + } + data = static_cast<char*>(img->planes[UHDR_PLANE_U]); + stride = img->stride[UHDR_PLANE_U] * bpp; + for (unsigned i = 0; i < img->h; i++, data += stride) { + ofd.write(data, length); + } + data = static_cast<char*>(img->planes[UHDR_PLANE_V]); + stride = img->stride[UHDR_PLANE_V] * bpp; + for (unsigned i = 0; i < img->h; i++, data += stride) { + ofd.write(data, length); + } + return true; + } + return false; + } + std::cerr << "unable to write to file : " << filename << std::endl; + return false; +} + class UltraHdrAppInput { public: UltraHdrAppInput(const char* p010File, const char* yuv420File, const char* yuv420JpegFile, - size_t width, size_t height, - ultrahdr_color_gamut p010Cg = ULTRAHDR_COLORGAMUT_BT709, - ultrahdr_color_gamut yuv420Cg = ULTRAHDR_COLORGAMUT_BT709, - ultrahdr_transfer_function tf = ULTRAHDR_TF_HLG, int quality = 100, - ultrahdr_output_format of = ULTRAHDR_OUTPUT_HDR_HLG) + const char* gainmapJpegFile, const char* gainmapMetadataCfgFile, size_t width, + size_t height, uhdr_color_gamut_t p010Cg = UHDR_CG_BT_709, + uhdr_color_gamut_t yuv420Cg = UHDR_CG_BT_709, + uhdr_color_transfer_t p010Tf = UHDR_CT_HLG, int quality = 100, + uhdr_color_transfer_t oTf = UHDR_CT_HLG, + uhdr_img_fmt_t oFmt = UHDR_IMG_FMT_32bppRGBA1010102) : mP010File(p010File), mYuv420File(yuv420File), mYuv420JpegFile(yuv420JpegFile), + mGainMapJpegFile(gainmapJpegFile), + mGainMapMetadataCfgFile(gainmapMetadataCfgFile), mJpegRFile(nullptr), mWidth(width), mHeight(height), mP010Cg(p010Cg), mYuv420Cg(yuv420Cg), - mTf(tf), + mP010Tf(p010Tf), mQuality(quality), - mOf(of), + mOTf(oTf), + mOfmt(oFmt), mMode(0){}; - UltraHdrAppInput(const char* jpegRFile, ultrahdr_output_format of = ULTRAHDR_OUTPUT_HDR_HLG) + UltraHdrAppInput(const char* jpegRFile, uhdr_color_transfer_t oTf = UHDR_CT_HLG, + uhdr_img_fmt_t oFmt = UHDR_IMG_FMT_32bppRGBA1010102) : mP010File(nullptr), mYuv420File(nullptr), mJpegRFile(jpegRFile), mWidth(0), mHeight(0), - mP010Cg(ULTRAHDR_COLORGAMUT_UNSPECIFIED), - mYuv420Cg(ULTRAHDR_COLORGAMUT_UNSPECIFIED), - mTf(ULTRAHDR_TF_UNSPECIFIED), + mP010Cg(UHDR_CG_UNSPECIFIED), + mYuv420Cg(UHDR_CG_UNSPECIFIED), + mP010Tf(UHDR_CT_UNSPECIFIED), mQuality(100), - mOf(of), + mOTf(oTf), + mOfmt(oFmt), mMode(1){}; ~UltraHdrAppInput() { - if (mRawP010Image.data) free(mRawP010Image.data); - if (mRawP010Image.chroma_data) free(mRawP010Image.chroma_data); - if (mRawRgba1010102Image.data) free(mRawRgba1010102Image.data); - if (mRawRgba1010102Image.chroma_data) free(mRawRgba1010102Image.chroma_data); - if (mRawYuv420Image.data) free(mRawYuv420Image.data); - if (mRawYuv420Image.chroma_data) free(mRawYuv420Image.chroma_data); - if (mRawRgba8888Image.data) free(mRawRgba8888Image.data); - if (mRawRgba8888Image.chroma_data) free(mRawRgba8888Image.chroma_data); + int count = sizeof mRawP010Image.planes / sizeof mRawP010Image.planes[UHDR_PLANE_Y]; + for (int i = 0; i < count; i++) { + if (mRawP010Image.planes[i]) { + free(mRawP010Image.planes[i]); + mRawP010Image.planes[i] = nullptr; + } + if (mRawRgba1010102Image.planes[i]) { + free(mRawRgba1010102Image.planes[i]); + mRawRgba1010102Image.planes[i] = nullptr; + } + if (mRawYuv420Image.planes[i]) { + free(mRawYuv420Image.planes[i]); + mRawYuv420Image.planes[i] = nullptr; + } + if (mRawRgba8888Image.planes[i]) { + free(mRawRgba8888Image.planes[i]); + mRawRgba8888Image.planes[i] = nullptr; + } + if (mDestImage.planes[i]) { + free(mDestImage.planes[i]); + mDestImage.planes[i] = nullptr; + } + if (mDestYUV444Image.planes[i]) { + free(mDestYUV444Image.planes[i]); + mDestYUV444Image.planes[i] = nullptr; + } + } if (mJpegImgR.data) free(mJpegImgR.data); - if (mDestImage.data) free(mDestImage.data); - if (mDestImage.chroma_data) free(mDestImage.chroma_data); - if (mDestYUV444Image.data) free(mDestYUV444Image.data); - if (mDestYUV444Image.chroma_data) free(mDestYUV444Image.chroma_data); } bool fillJpegRImageHandle(); @@ -223,6 +307,8 @@ class UltraHdrAppInput { bool convertP010ToRGBImage(); bool fillYuv420ImageHandle(); bool fillYuv420JpegImageHandle(); + bool fillGainMapJpegImageHandle(); + bool fillGainMapMetadataDescriptor(); bool convertYuv420ToRGBImage(); bool convertRgba8888ToYUV444Image(); bool convertRgba1010102ToYUV444Image(); @@ -236,65 +322,145 @@ class UltraHdrAppInput { const char* mP010File; const char* mYuv420File; const char* mYuv420JpegFile; + const char *mGainMapJpegFile; + const char *mGainMapMetadataCfgFile; const char* mJpegRFile; const int mWidth; const int mHeight; - const ultrahdr_color_gamut mP010Cg; - const ultrahdr_color_gamut mYuv420Cg; - const ultrahdr_transfer_function mTf; + const uhdr_color_gamut_t mP010Cg; + const uhdr_color_gamut_t mYuv420Cg; + const uhdr_color_transfer_t mP010Tf; const int mQuality; - const ultrahdr_output_format mOf; + const uhdr_color_transfer_t mOTf; + const uhdr_img_fmt mOfmt; const int mMode; - jpegr_uncompressed_struct mRawP010Image{}; - jpegr_uncompressed_struct mRawRgba1010102Image{}; - jpegr_uncompressed_struct mRawYuv420Image{}; - jpegr_compressed_struct mYuv420JpegImage{}; - jpegr_uncompressed_struct mRawRgba8888Image{}; - jpegr_compressed_struct mJpegImgR{}; - jpegr_uncompressed_struct mDestImage{}; - jpegr_uncompressed_struct mDestYUV444Image{}; + + uhdr_raw_image_t mRawP010Image{}; + uhdr_raw_image_t mRawRgba1010102Image{}; + uhdr_raw_image_t mRawYuv420Image{}; + uhdr_compressed_image_t mYuv420JpegImage{}; + uhdr_compressed_image_t mGainMapJpegImage{}; + uhdr_gainmap_metadata mMetadata{}; + uhdr_raw_image_t mRawRgba8888Image{}; + uhdr_compressed_image_t mJpegImgR{}; + uhdr_raw_image_t mDestImage{}; + uhdr_raw_image_t mDestYUV444Image{}; double mPsnr[3]{}; }; bool UltraHdrAppInput::fillP010ImageHandle() { const int bpp = 2; int p010Size = mWidth * mHeight * bpp * 1.5; - mRawP010Image.width = mWidth; - mRawP010Image.height = mHeight; - mRawP010Image.colorGamut = mP010Cg; - return loadFile(mP010File, mRawP010Image.data, p010Size); + mRawP010Image.fmt = UHDR_IMG_FMT_24bppYCbCrP010; + mRawP010Image.cg = mP010Cg; + mRawP010Image.ct = mP010Tf; + mRawP010Image.range = UHDR_CR_LIMITED_RANGE; + mRawP010Image.w = mWidth; + mRawP010Image.h = mHeight; + mRawP010Image.planes[UHDR_PLANE_Y] = malloc(mWidth * mHeight * bpp); + mRawP010Image.planes[UHDR_PLANE_UV] = malloc((mWidth / 2) * (mHeight / 2) * bpp * 2); + mRawP010Image.planes[UHDR_PLANE_V] = nullptr; + mRawP010Image.stride[UHDR_PLANE_Y] = mWidth; + mRawP010Image.stride[UHDR_PLANE_UV] = mWidth; + mRawP010Image.stride[UHDR_PLANE_V] = 0; + return loadFile(mP010File, &mRawP010Image); } bool UltraHdrAppInput::fillYuv420ImageHandle() { int yuv420Size = mWidth * mHeight * 1.5; - mRawYuv420Image.width = mWidth; - mRawYuv420Image.height = mHeight; - mRawYuv420Image.colorGamut = mYuv420Cg; - return loadFile(mYuv420File, mRawYuv420Image.data, yuv420Size); + mRawYuv420Image.fmt = UHDR_IMG_FMT_12bppYCbCr420; + mRawYuv420Image.cg = mYuv420Cg; + mRawYuv420Image.ct = UHDR_CT_SRGB; + mRawYuv420Image.range = UHDR_CR_FULL_RANGE; + mRawYuv420Image.w = mWidth; + mRawYuv420Image.h = mHeight; + mRawYuv420Image.planes[UHDR_PLANE_Y] = malloc(mWidth * mHeight); + mRawYuv420Image.planes[UHDR_PLANE_U] = malloc((mWidth / 2) * (mHeight / 2)); + mRawYuv420Image.planes[UHDR_PLANE_V] = malloc((mWidth / 2) * (mHeight / 2)); + mRawYuv420Image.stride[UHDR_PLANE_Y] = mWidth; + mRawYuv420Image.stride[UHDR_PLANE_U] = mWidth / 2; + mRawYuv420Image.stride[UHDR_PLANE_V] = mWidth / 2; + return loadFile(mYuv420File, &mRawYuv420Image); } bool UltraHdrAppInput::fillYuv420JpegImageHandle() { std::ifstream ifd(mYuv420JpegFile, std::ios::binary | std::ios::ate); if (ifd.good()) { int size = ifd.tellg(); - mYuv420JpegImage.length = size; - mYuv420JpegImage.maxLength = size; + mYuv420JpegImage.capacity = size; + mYuv420JpegImage.data_sz = size; mYuv420JpegImage.data = nullptr; - mYuv420JpegImage.colorGamut = mYuv420Cg; + mYuv420JpegImage.cg = mYuv420Cg; + mYuv420JpegImage.ct = UHDR_CT_UNSPECIFIED; + mYuv420JpegImage.range = UHDR_CR_UNSPECIFIED; ifd.close(); return loadFile(mYuv420JpegFile, mYuv420JpegImage.data, size); } return false; } +bool UltraHdrAppInput::fillGainMapJpegImageHandle() { + std::ifstream ifd(mGainMapJpegFile, std::ios::binary | std::ios::ate); + if (ifd.good()) { + int size = ifd.tellg(); + mGainMapJpegImage.capacity = size; + mGainMapJpegImage.data_sz = size; + mGainMapJpegImage.data = nullptr; + mGainMapJpegImage.cg = UHDR_CG_UNSPECIFIED; + mGainMapJpegImage.ct = UHDR_CT_UNSPECIFIED; + mGainMapJpegImage.range = UHDR_CR_UNSPECIFIED; + ifd.close(); + return loadFile(mGainMapJpegFile, mGainMapJpegImage.data, size); + } + return false; +} + +void parse_argument(uhdr_gainmap_metadata* metadata, char* argument, float* value) { + if (!strcmp(argument, "maxContentBoost")) + metadata->max_content_boost = *value; + else if (!strcmp(argument, "minContentBoost")) + metadata->min_content_boost = *value; + else if (!strcmp(argument, "gamma")) + metadata->gamma = *value; + else if (!strcmp(argument, "offsetSdr")) + metadata->offset_sdr = *value; + else if (!strcmp(argument, "offsetHdr")) + metadata->offset_hdr = *value; + else if (!strcmp(argument, "hdrCapacityMin")) + metadata->hdr_capacity_min = *value; + else if (!strcmp(argument, "hdrCapacityMax")) + metadata->hdr_capacity_max = *value; + else + std::cout << " Ignoring argument " << argument << std::endl; +} + +bool UltraHdrAppInput::fillGainMapMetadataDescriptor() { + std::ifstream file(mGainMapMetadataCfgFile); + if (!file.is_open()) { + return false; + } + std::string line; + char argument[128]; + float value; + while (std::getline(file, line)) { + if (sscanf(line.c_str(), "--%s %f", argument, &value) == 2) { + parse_argument(&mMetadata, argument, &value); + } + } + file.close(); + return true; +} + bool UltraHdrAppInput::fillJpegRImageHandle() { std::ifstream ifd(mJpegRFile, std::ios::binary | std::ios::ate); if (ifd.good()) { int size = ifd.tellg(); - mJpegImgR.length = size; - mJpegImgR.maxLength = size; + mJpegImgR.capacity = size; + mJpegImgR.data_sz = size; mJpegImgR.data = nullptr; - mJpegImgR.colorGamut = mYuv420Cg; + mYuv420JpegImage.cg = UHDR_CG_UNSPECIFIED; + mYuv420JpegImage.ct = UHDR_CT_UNSPECIFIED; + mYuv420JpegImage.range = UHDR_CR_UNSPECIFIED; ifd.close(); return loadFile(mJpegRFile, mJpegImgR.data, size); } @@ -302,140 +468,187 @@ bool UltraHdrAppInput::fillJpegRImageHandle() { } bool UltraHdrAppInput::encode() { - if (!fillP010ImageHandle()) return false; - if (mYuv420File != nullptr && !fillYuv420ImageHandle()) return false; - if (mYuv420JpegFile != nullptr && !fillYuv420JpegImageHandle()) return false; - - mJpegImgR.maxLength = (std::max)(static_cast<size_t>(8 * 1024) /* min size 8kb */, - mRawP010Image.width * mRawP010Image.height * 3 * 2); - mJpegImgR.data = malloc(mJpegImgR.maxLength); - if (mJpegImgR.data == nullptr) { - std::cerr << "unable to allocate memory to store compressed image" << std::endl; - return false; +#define RET_IF_ERR(x) \ + { \ + uhdr_error_info_t status = (x); \ + if (status.error_code != UHDR_CODEC_OK) { \ + if (status.has_detail) { \ + std::cerr << status.detail << std::endl; \ + } \ + uhdr_release_encoder(handle); \ + return false; \ + } \ } - JpegR jpegHdr; - status_t status = JPEGR_UNKNOWN_ERROR; + uhdr_codec_private_t* handle = uhdr_create_encoder(); + if (mP010File != nullptr) { + if (!fillP010ImageHandle()) { + std::cerr << " failed to load file " << mP010File << std::endl; + return false; + } + RET_IF_ERR(uhdr_enc_set_raw_image(handle, &mRawP010Image, UHDR_HDR_IMG)) + } + if (mYuv420File != nullptr) { + if (!fillYuv420ImageHandle()) { + std::cerr << " failed to load file " << mYuv420File << std::endl; + return false; + } + RET_IF_ERR(uhdr_enc_set_raw_image(handle, &mRawYuv420Image, UHDR_SDR_IMG)) + } + if (mYuv420JpegFile != nullptr) { + if (!fillYuv420JpegImageHandle()) { + std::cerr << " failed to load file " << mYuv420JpegFile << std::endl; + return false; + } + RET_IF_ERR(uhdr_enc_set_compressed_image( + handle, &mYuv420JpegImage, + (mGainMapJpegFile != nullptr && mGainMapMetadataCfgFile != nullptr) ? UHDR_BASE_IMG + : UHDR_SDR_IMG)) + } + if (mGainMapJpegFile != nullptr && mGainMapMetadataCfgFile != nullptr) { + if (!fillGainMapJpegImageHandle()) { + std::cerr << " failed to load file " << mGainMapJpegFile << std::endl; + return false; + } + if (!fillGainMapMetadataDescriptor()) { + std::cerr << " failed to read config file " << mGainMapMetadataCfgFile << std::endl; + return false; + } + RET_IF_ERR(uhdr_enc_set_gainmap_image(handle, &mGainMapJpegImage, &mMetadata)) + } + RET_IF_ERR(uhdr_enc_set_quality(handle, mQuality, UHDR_BASE_IMG)) #ifdef PROFILE_ENABLE const int profileCount = 10; Profiler profileEncode; profileEncode.timerStart(); for (auto i = 0; i < profileCount; i++) { #endif - if (mYuv420File == nullptr && mYuv420JpegFile == nullptr) { // api-0 - status = jpegHdr.encodeJPEGR(&mRawP010Image, mTf, &mJpegImgR, mQuality, nullptr); - if (JPEGR_NO_ERROR != status) { - std::cerr << "Encountered error during encodeJPEGR call, error code " << status - << std::endl; - return false; - } - } else if (mYuv420File != nullptr && mYuv420JpegFile == nullptr) { // api-1 - status = - jpegHdr.encodeJPEGR(&mRawP010Image, &mRawYuv420Image, mTf, &mJpegImgR, mQuality, nullptr); - if (JPEGR_NO_ERROR != status) { - std::cerr << "Encountered error during encodeJPEGR call, error code " << status - << std::endl; - return false; - } - } else if (mYuv420File != nullptr && mYuv420JpegFile != nullptr) { // api-2 - status = - jpegHdr.encodeJPEGR(&mRawP010Image, &mRawYuv420Image, &mYuv420JpegImage, mTf, &mJpegImgR); - if (JPEGR_NO_ERROR != status) { - std::cerr << "Encountered error during encodeJPEGR call, error code " << status - << std::endl; - return false; - } - } else if (mYuv420File == nullptr && mYuv420JpegFile != nullptr) { // api-3 - status = jpegHdr.encodeJPEGR(&mRawP010Image, &mYuv420JpegImage, mTf, &mJpegImgR); - if (JPEGR_NO_ERROR != status) { - std::cerr << "Encountered error during encodeJPEGR call, error code " << status - << std::endl; - return false; - } - } + RET_IF_ERR(uhdr_encode(handle)) #ifdef PROFILE_ENABLE } profileEncode.timerStop(); auto avgEncTime = profileEncode.elapsedTime() / (profileCount * 1000.f); printf("Average encode time for res %d x %d is %f ms \n", mWidth, mHeight, avgEncTime); #endif - writeFile("out.jpeg", mJpegImgR.data, mJpegImgR.length); + +#undef RET_IF_ERR + + auto output = uhdr_get_encoded_stream(handle); + + // for decoding + mJpegImgR.data = malloc(output->data_sz); + memcpy(mJpegImgR.data, output->data, output->data_sz); + mJpegImgR.capacity = mJpegImgR.data_sz = output->data_sz; + mJpegImgR.cg = output->cg; + mJpegImgR.ct = output->ct; + mJpegImgR.range = output->range; + writeFile("out.jpeg", output->data, output->data_sz); + uhdr_release_encoder(handle); + return true; } bool UltraHdrAppInput::decode() { - if (mMode == 1 && !fillJpegRImageHandle()) return false; - std::vector<uint8_t> iccData(0); - std::vector<uint8_t> exifData(0); - jpegr_info_struct info{}; - JpegR jpegHdr; - status_t status = jpegHdr.getJPEGRInfo(&mJpegImgR, &info); - if (JPEGR_NO_ERROR == status) { - size_t outSize = info.width * info.height * ((mOf == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4); - mDestImage.data = malloc(outSize); - if (mDestImage.data == nullptr) { - std::cerr << "failed to allocate memory to store decoded output" << std::endl; - return false; - } + if (mMode == 1 && !fillJpegRImageHandle()) { + std::cerr << " failed to load file " << mJpegRFile << std::endl; + return false; + } + +#define RET_IF_ERR(x) \ + { \ + uhdr_error_info_t status = (x); \ + if (status.error_code != UHDR_CODEC_OK) { \ + if (status.has_detail) { \ + std::cerr << status.detail << std::endl; \ + } \ + uhdr_release_decoder(handle); \ + return false; \ + } \ + } + + uhdr_codec_private_t* handle = uhdr_create_decoder(); + RET_IF_ERR(uhdr_dec_set_image(handle, &mJpegImgR)) + RET_IF_ERR(uhdr_dec_set_out_color_transfer(handle, mOTf)) + RET_IF_ERR(uhdr_dec_set_out_img_format(handle, mOfmt)) + #ifdef PROFILE_ENABLE - const int profileCount = 10; - Profiler profileDecode; - profileDecode.timerStart(); - for (auto i = 0; i < profileCount; i++) { + const int profileCount = 10; + Profiler profileDecode; + profileDecode.timerStart(); + for (auto i = 0; i < profileCount; i++) { #endif - status = - jpegHdr.decodeJPEGR(&mJpegImgR, &mDestImage, FLT_MAX, nullptr, mOf, nullptr, nullptr); - if (JPEGR_NO_ERROR != status) { - std::cerr << "Encountered error during decodeJPEGR call, error code " << status - << std::endl; - return false; - } + RET_IF_ERR(uhdr_decode(handle)) #ifdef PROFILE_ENABLE - } - profileDecode.timerStop(); - auto avgDecTime = profileDecode.elapsedTime() / (profileCount * 1000.f); - printf("Average decode time for res %ld x %ld is %f ms \n", info.width, info.height, - avgDecTime); + } + profileDecode.timerStop(); + auto avgDecTime = profileDecode.elapsedTime() / (profileCount * 1000.f); + printf("Average decode time for res %ld x %ld is %f ms \n", info.width, info.height, avgDecTime); #endif - writeFile("outrgb.raw", mDestImage.data, outSize); - } else { - std::cerr << "Encountered error during getJPEGRInfo call, error code " << status << std::endl; - return false; + +#undef RET_IF_ERR + + uhdr_raw_image_t* output = uhdr_get_decoded_image(handle); + + mDestImage.fmt = output->fmt; + mDestImage.cg = output->cg; + mDestImage.ct = output->ct; + mDestImage.range = output->range; + mDestImage.w = output->w; + mDestImage.h = output->h; + int bpp = (output->fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat) ? 8 : 4; + mDestImage.planes[UHDR_PLANE_PACKED] = malloc(output->w * output->h * bpp); + char* inData = static_cast<char*>(output->planes[UHDR_PLANE_PACKED]); + char* outData = static_cast<char*>(mDestImage.planes[UHDR_PLANE_PACKED]); + const size_t inStride = output->stride[UHDR_PLANE_PACKED] * bpp; + const size_t outStride = output->w * bpp; + mDestImage.stride[UHDR_PLANE_PACKED] = output->w; + const size_t length = output->w * bpp; + for (unsigned i = 0; i < output->h; i++, inData += inStride, outData += outStride) { + memcpy(outData, inData, length); } + writeFile("outrgb.raw", output); + uhdr_release_decoder(handle); + return true; } +#define CLIP3(x, min, max) ((x) < (min)) ? (min) : ((x) > (max)) ? (max) : (x) bool UltraHdrAppInput::convertP010ToRGBImage() { const float* coeffs = BT2020YUVtoRGBMatrix; - if (mP010Cg == ULTRAHDR_COLORGAMUT_BT709) { + if (mP010Cg == UHDR_CG_BT_709) { coeffs = BT709YUVtoRGBMatrix; - } else if (mP010Cg == ULTRAHDR_COLORGAMUT_BT2100) { + } else if (mP010Cg == UHDR_CG_BT_2100) { coeffs = BT2020YUVtoRGBMatrix; - } else if (mP010Cg == ULTRAHDR_COLORGAMUT_P3) { + } else if (mP010Cg == UHDR_CG_DISPLAY_P3) { coeffs = BT601YUVtoRGBMatrix; } else { std::cerr << "color matrix not present for gamut " << mP010Cg << " using BT2020Matrix" << std::endl; } - mRawRgba1010102Image.data = malloc(mRawP010Image.width * mRawP010Image.height * 4); - if (mRawRgba1010102Image.data == nullptr) { - std::cerr << "failed to allocate memory to store Rgba1010102" << std::endl; - return false; - } - mRawRgba1010102Image.width = mRawP010Image.width; - mRawRgba1010102Image.height = mRawP010Image.height; - mRawRgba1010102Image.colorGamut = mRawP010Image.colorGamut; - uint32_t* rgbData = static_cast<uint32_t*>(mRawRgba1010102Image.data); - uint16_t* y = static_cast<uint16_t*>(mRawP010Image.data); - uint16_t* u = y + mRawP010Image.width * mRawP010Image.height; + mRawRgba1010102Image.fmt = UHDR_IMG_FMT_32bppRGBA1010102; + mRawRgba1010102Image.cg = mRawP010Image.cg; + mRawRgba1010102Image.ct = mRawP010Image.ct; + mRawRgba1010102Image.range = UHDR_CR_FULL_RANGE; + mRawRgba1010102Image.w = mRawP010Image.w; + mRawRgba1010102Image.h = mRawP010Image.h; + mRawRgba1010102Image.planes[UHDR_PLANE_PACKED] = malloc(mRawP010Image.w * mRawP010Image.h * 4); + mRawRgba1010102Image.planes[UHDR_PLANE_U] = nullptr; + mRawRgba1010102Image.planes[UHDR_PLANE_V] = nullptr; + mRawRgba1010102Image.stride[UHDR_PLANE_PACKED] = mWidth; + mRawRgba1010102Image.stride[UHDR_PLANE_U] = 0; + mRawRgba1010102Image.stride[UHDR_PLANE_V] = 0; + + uint32_t* rgbData = static_cast<uint32_t*>(mRawRgba1010102Image.planes[UHDR_PLANE_PACKED]); + uint16_t* y = static_cast<uint16_t*>(mRawP010Image.planes[UHDR_PLANE_Y]); + uint16_t* u = static_cast<uint16_t*>(mRawP010Image.planes[UHDR_PLANE_UV]); uint16_t* v = u + 1; - for (size_t i = 0; i < mRawP010Image.height; i++) { - for (size_t j = 0; j < mRawP010Image.width; j++) { - float y0 = float(y[mRawP010Image.width * i + j] >> 6); - float u0 = float(u[mRawP010Image.width * (i / 2) + (j / 2) * 2] >> 6); - float v0 = float(v[mRawP010Image.width * (i / 2) + (j / 2) * 2] >> 6); + for (size_t i = 0; i < mRawP010Image.h; i++) { + for (size_t j = 0; j < mRawP010Image.w; j++) { + float y0 = float(y[mRawP010Image.stride[UHDR_PLANE_Y] * i + j] >> 6); + float u0 = float(u[mRawP010Image.stride[UHDR_PLANE_UV] * (i / 2) + (j / 2) * 2] >> 6); + float v0 = float(v[mRawP010Image.stride[UHDR_PLANE_UV] * (i / 2) + (j / 2) * 2] >> 6); y0 = CLIP3(y0, 64.0f, 940.0f); u0 = CLIP3(u0, 64.0f, 960.0f); @@ -462,31 +675,35 @@ bool UltraHdrAppInput::convertP010ToRGBImage() { rgbData++; } } - writeFile("inRgba1010102.raw", mRawRgba1010102Image.data, - mRawP010Image.width * mRawP010Image.height * 4); + writeFile("inRgba1010102.raw", &mRawRgba1010102Image); return true; } bool UltraHdrAppInput::convertYuv420ToRGBImage() { - mRawRgba8888Image.data = malloc(mRawYuv420Image.width * mRawYuv420Image.height * 4); - if (mRawRgba8888Image.data == nullptr) { - std::cerr << "failed to allocate memory to store rgba888" << std::endl; - return false; - } - mRawRgba8888Image.width = mRawYuv420Image.width; - mRawRgba8888Image.height = mRawYuv420Image.height; - mRawRgba8888Image.colorGamut = mRawYuv420Image.colorGamut; - uint32_t* rgbData = static_cast<uint32_t*>(mRawRgba8888Image.data); - uint8_t* y = static_cast<uint8_t*>(mRawYuv420Image.data); - uint8_t* u = y + (mRawYuv420Image.width * mRawYuv420Image.height); - uint8_t* v = u + (mRawYuv420Image.width * mRawYuv420Image.height / 4); + mRawRgba8888Image.fmt = UHDR_IMG_FMT_32bppRGBA8888; + mRawRgba8888Image.cg = mRawYuv420Image.cg; + mRawRgba8888Image.ct = mRawYuv420Image.ct; + mRawRgba8888Image.range = UHDR_CR_FULL_RANGE; + mRawRgba8888Image.w = mRawYuv420Image.w; + mRawRgba8888Image.h = mRawYuv420Image.h; + mRawRgba8888Image.planes[UHDR_PLANE_PACKED] = malloc(mRawYuv420Image.w * mRawYuv420Image.h * 4); + mRawRgba8888Image.planes[UHDR_PLANE_U] = nullptr; + mRawRgba8888Image.planes[UHDR_PLANE_V] = nullptr; + mRawRgba8888Image.stride[UHDR_PLANE_PACKED] = mWidth; + mRawRgba8888Image.stride[UHDR_PLANE_U] = 0; + mRawRgba8888Image.stride[UHDR_PLANE_V] = 0; + + uint32_t* rgbData = static_cast<uint32_t*>(mRawRgba8888Image.planes[UHDR_PLANE_PACKED]); + uint8_t* y = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_Y]); + uint8_t* u = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_U]); + uint8_t* v = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_V]); const float* coeffs = BT601YUVtoRGBMatrix; - for (size_t i = 0; i < mRawYuv420Image.height; i++) { - for (size_t j = 0; j < mRawYuv420Image.width; j++) { - float y0 = float(y[mRawYuv420Image.width * i + j]); - float u0 = float(u[mRawYuv420Image.width / 2 * (i / 2) + (j / 2)] - 128); - float v0 = float(v[mRawYuv420Image.width / 2 * (i / 2) + (j / 2)] - 128); + for (size_t i = 0; i < mRawYuv420Image.h; i++) { + for (size_t j = 0; j < mRawYuv420Image.w; j++) { + float y0 = float(y[mRawYuv420Image.stride[UHDR_PLANE_Y] * i + j]); + float u0 = float(u[mRawYuv420Image.stride[UHDR_PLANE_U] * (i / 2) + (j / 2)] - 128); + float v0 = float(v[mRawYuv420Image.stride[UHDR_PLANE_V] * (i / 2) + (j / 2)] - 128); y0 /= 255.0f; u0 /= 255.0f; @@ -512,33 +729,36 @@ bool UltraHdrAppInput::convertYuv420ToRGBImage() { rgbData++; } } - writeFile("inRgba8888.raw", mRawRgba8888Image.data, - mRawYuv420Image.width * mRawYuv420Image.height * 4); + writeFile("inRgba8888.raw", &mRawRgba8888Image); return true; } bool UltraHdrAppInput::convertRgba8888ToYUV444Image() { - mDestYUV444Image.data = malloc(mDestImage.width * mDestImage.height * 3); - if (mDestYUV444Image.data == nullptr) { - std::cerr << "failed to allocate memory to store yuv444" << std::endl; - return false; - } - mDestYUV444Image.width = mDestImage.width; - mDestYUV444Image.height = mDestImage.height; - mDestYUV444Image.colorGamut = mDestImage.colorGamut; - - uint32_t* rgbData = static_cast<uint32_t*>(mDestImage.data); - - uint8_t* yData = static_cast<uint8_t*>(mDestYUV444Image.data); - uint8_t* uData = yData + (mDestYUV444Image.width * mDestYUV444Image.height); - uint8_t* vData = uData + (mDestYUV444Image.width * mDestYUV444Image.height); + mDestYUV444Image.fmt = static_cast<uhdr_img_fmt_t>(UHDR_IMG_FMT_24bppYCbCr444); + mDestYUV444Image.cg = mDestImage.cg; + mDestYUV444Image.ct = mDestImage.ct; + mDestYUV444Image.range = UHDR_CR_FULL_RANGE; + mDestYUV444Image.w = mDestImage.w; + mDestYUV444Image.h = mDestImage.h; + mDestYUV444Image.planes[UHDR_PLANE_Y] = malloc(mDestImage.w * mDestImage.h); + mDestYUV444Image.planes[UHDR_PLANE_U] = malloc(mDestImage.w * mDestImage.h); + mDestYUV444Image.planes[UHDR_PLANE_V] = malloc(mDestImage.w * mDestImage.h); + mDestYUV444Image.stride[UHDR_PLANE_Y] = mWidth; + mDestYUV444Image.stride[UHDR_PLANE_U] = mWidth; + mDestYUV444Image.stride[UHDR_PLANE_V] = mWidth; + + uint32_t* rgbData = static_cast<uint32_t*>(mDestImage.planes[UHDR_PLANE_PACKED]); + + uint8_t* yData = static_cast<uint8_t*>(mDestYUV444Image.planes[UHDR_PLANE_Y]); + uint8_t* uData = static_cast<uint8_t*>(mDestYUV444Image.planes[UHDR_PLANE_U]); + uint8_t* vData = static_cast<uint8_t*>(mDestYUV444Image.planes[UHDR_PLANE_V]); const float* coeffs = BT601RGBtoYUVMatrix; - for (size_t i = 0; i < mDestImage.height; i++) { - for (size_t j = 0; j < mDestImage.width; j++) { - float r0 = float(rgbData[mDestImage.width * i + j] & 0xff); - float g0 = float((rgbData[mDestImage.width * i + j] >> 8) & 0xff); - float b0 = float((rgbData[mDestImage.width * i + j] >> 16) & 0xff); + for (size_t i = 0; i < mDestImage.h; i++) { + for (size_t j = 0; j < mDestImage.w; j++) { + float r0 = float(rgbData[mDestImage.stride[UHDR_PLANE_PACKED] * i + j] & 0xff); + float g0 = float((rgbData[mDestImage.stride[UHDR_PLANE_PACKED] * i + j] >> 8) & 0xff); + float b0 = float((rgbData[mDestImage.stride[UHDR_PLANE_PACKED] * i + j] >> 16) & 0xff); r0 /= 255.0f; g0 /= 255.0f; @@ -556,49 +776,52 @@ bool UltraHdrAppInput::convertRgba8888ToYUV444Image() { u = CLIP3(u, 0.0f, 255.0f); v = CLIP3(v, 0.0f, 255.0f); - yData[mDestYUV444Image.width * i + j] = uint8_t(y); - uData[mDestYUV444Image.width * i + j] = uint8_t(u); - vData[mDestYUV444Image.width * i + j] = uint8_t(v); + yData[mDestYUV444Image.stride[UHDR_PLANE_Y] * i + j] = uint8_t(y); + uData[mDestYUV444Image.stride[UHDR_PLANE_U] * i + j] = uint8_t(u); + vData[mDestYUV444Image.stride[UHDR_PLANE_V] * i + j] = uint8_t(v); } } - writeFile("outyuv444.yuv", mDestYUV444Image.data, - mDestYUV444Image.width * mDestYUV444Image.height * 3); + writeFile("outyuv444.yuv", &mDestYUV444Image); return true; } bool UltraHdrAppInput::convertRgba1010102ToYUV444Image() { const float* coeffs = BT2020RGBtoYUVMatrix; - if (mP010Cg == ULTRAHDR_COLORGAMUT_BT709) { + if (mP010Cg == UHDR_CG_BT_709) { coeffs = BT709RGBtoYUVMatrix; - } else if (mP010Cg == ULTRAHDR_COLORGAMUT_BT2100) { + } else if (mP010Cg == UHDR_CG_BT_2100) { coeffs = BT2020RGBtoYUVMatrix; - } else if (mP010Cg == ULTRAHDR_COLORGAMUT_P3) { + } else if (mP010Cg == UHDR_CG_DISPLAY_P3) { coeffs = BT601RGBtoYUVMatrix; } else { std::cerr << "color matrix not present for gamut " << mP010Cg << " using BT2020Matrix" << std::endl; } - mDestYUV444Image.data = malloc(mDestImage.width * mDestImage.height * 3 * 2); - if (mDestYUV444Image.data == nullptr) { - std::cerr << "failed to allocate memory to store yuv444" << std::endl; - return false; - } - mDestYUV444Image.width = mDestImage.width; - mDestYUV444Image.height = mDestImage.height; - mDestYUV444Image.colorGamut = mDestImage.colorGamut; - - uint32_t* rgbData = static_cast<uint32_t*>(mDestImage.data); - - uint16_t* yData = static_cast<uint16_t*>(mDestYUV444Image.data); - uint16_t* uData = yData + (mDestYUV444Image.width * mDestYUV444Image.height); - uint16_t* vData = uData + (mDestYUV444Image.width * mDestYUV444Image.height); - - for (size_t i = 0; i < mDestImage.height; i++) { - for (size_t j = 0; j < mDestImage.width; j++) { - float r0 = float(rgbData[mDestImage.width * i + j] & 0x3ff); - float g0 = float((rgbData[mDestImage.width * i + j] >> 10) & 0x3ff); - float b0 = float((rgbData[mDestImage.width * i + j] >> 20) & 0x3ff); + mDestYUV444Image.fmt = static_cast<uhdr_img_fmt_t>(UHDR_IMG_FMT_48bppYCbCr444); + mDestYUV444Image.cg = mDestImage.cg; + mDestYUV444Image.ct = mDestImage.ct; + mDestYUV444Image.range = UHDR_CR_FULL_RANGE; + mDestYUV444Image.w = mDestImage.w; + mDestYUV444Image.h = mDestImage.h; + mDestYUV444Image.planes[UHDR_PLANE_Y] = malloc(mDestImage.w * mDestImage.h * 2); + mDestYUV444Image.planes[UHDR_PLANE_U] = malloc(mDestImage.w * mDestImage.h * 2); + mDestYUV444Image.planes[UHDR_PLANE_V] = malloc(mDestImage.w * mDestImage.h * 2); + mDestYUV444Image.stride[UHDR_PLANE_Y] = mWidth; + mDestYUV444Image.stride[UHDR_PLANE_U] = mWidth; + mDestYUV444Image.stride[UHDR_PLANE_V] = mWidth; + + uint32_t* rgbData = static_cast<uint32_t*>(mDestImage.planes[UHDR_PLANE_PACKED]); + + uint16_t* yData = static_cast<uint16_t*>(mDestYUV444Image.planes[UHDR_PLANE_Y]); + uint16_t* uData = static_cast<uint16_t*>(mDestYUV444Image.planes[UHDR_PLANE_U]); + uint16_t* vData = static_cast<uint16_t*>(mDestYUV444Image.planes[UHDR_PLANE_V]); + + for (size_t i = 0; i < mDestImage.h; i++) { + for (size_t j = 0; j < mDestImage.w; j++) { + float r0 = float(rgbData[mDestImage.stride[UHDR_PLANE_PACKED] * i + j] & 0x3ff); + float g0 = float((rgbData[mDestImage.stride[UHDR_PLANE_PACKED] * i + j] >> 10) & 0x3ff); + float b0 = float((rgbData[mDestImage.stride[UHDR_PLANE_PACKED] * i + j] >> 20) & 0x3ff); r0 /= 1023.0f; g0 /= 1023.0f; @@ -616,35 +839,33 @@ bool UltraHdrAppInput::convertRgba1010102ToYUV444Image() { u = CLIP3(u, 64.0f, 960.0f); v = CLIP3(v, 64.0f, 960.0f); - yData[mDestYUV444Image.width * i + j] = uint16_t(y); - uData[mDestYUV444Image.width * i + j] = uint16_t(u); - vData[mDestYUV444Image.width * i + j] = uint16_t(v); + yData[mDestYUV444Image.stride[UHDR_PLANE_Y] * i + j] = uint16_t(y); + uData[mDestYUV444Image.stride[UHDR_PLANE_U] * i + j] = uint16_t(u); + vData[mDestYUV444Image.stride[UHDR_PLANE_V] * i + j] = uint16_t(v); } } - writeFile("outyuv444.yuv", mDestYUV444Image.data, - mDestYUV444Image.width * mDestYUV444Image.height * 3 * 2); + writeFile("outyuv444.yuv", &mDestYUV444Image); return true; } void UltraHdrAppInput::computeRGBHdrPSNR() { - if (mOf == ULTRAHDR_OUTPUT_SDR || mOf == ULTRAHDR_OUTPUT_HDR_LINEAR) { - std::cout << "psnr not supported for output format " << mOf << std::endl; + if (mOfmt != UHDR_IMG_FMT_32bppRGBA1010102) { + std::cout << "psnr not supported for output format " << mOfmt << std::endl; return; } - uint32_t* rgbDataSrc = static_cast<uint32_t*>(mRawRgba1010102Image.data); - uint32_t* rgbDataDst = static_cast<uint32_t*>(mDestImage.data); + uint32_t* rgbDataSrc = static_cast<uint32_t*>(mRawRgba1010102Image.planes[UHDR_PLANE_PACKED]); + uint32_t* rgbDataDst = static_cast<uint32_t*>(mDestImage.planes[UHDR_PLANE_PACKED]); if (rgbDataSrc == nullptr || rgbDataDst == nullptr) { std::cerr << "invalid src or dst pointer for psnr computation " << std::endl; return; } - if ((mOf == ULTRAHDR_OUTPUT_HDR_PQ && mTf != ULTRAHDR_TF_PQ) || - (mOf == ULTRAHDR_OUTPUT_HDR_HLG && mTf != ULTRAHDR_TF_HLG)) { + if (mOTf != mP010Tf) { std::cout << "input transfer function and output format are not compatible, psnr results " "may be unreliable" << std::endl; } uint64_t rSqError = 0, gSqError = 0, bSqError = 0; - for (size_t i = 0; i < mRawP010Image.width * mRawP010Image.height; i++) { + for (size_t i = 0; i < mRawP010Image.w * mRawP010Image.h; i++) { int rSrc = *rgbDataSrc & 0x3ff; int rDst = *rgbDataDst & 0x3ff; rSqError += (rSrc - rDst) * (rSrc - rDst); @@ -660,13 +881,13 @@ void UltraHdrAppInput::computeRGBHdrPSNR() { rgbDataSrc++; rgbDataDst++; } - double meanSquareError = (double)rSqError / (mRawP010Image.width * mRawP010Image.height); + double meanSquareError = (double)rSqError / (mRawP010Image.w * mRawP010Image.h); mPsnr[0] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100; - meanSquareError = (double)gSqError / (mRawP010Image.width * mRawP010Image.height); + meanSquareError = (double)gSqError / (mRawP010Image.w * mRawP010Image.h); mPsnr[1] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100; - meanSquareError = (double)bSqError / (mRawP010Image.width * mRawP010Image.height); + meanSquareError = (double)bSqError / (mRawP010Image.w * mRawP010Image.h); mPsnr[2] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100; std::cout << "psnr r :: " << mPsnr[0] << " psnr g :: " << mPsnr[1] << " psnr b :: " << mPsnr[2] @@ -674,19 +895,19 @@ void UltraHdrAppInput::computeRGBHdrPSNR() { } void UltraHdrAppInput::computeRGBSdrPSNR() { - if (mOf != ULTRAHDR_OUTPUT_SDR) { - std::cout << "psnr not supported for output format " << mOf << std::endl; + if (mOfmt != UHDR_IMG_FMT_32bppRGBA8888) { + std::cout << "psnr not supported for output format " << mOfmt << std::endl; return; } - uint32_t* rgbDataSrc = static_cast<uint32_t*>(mRawRgba8888Image.data); - uint32_t* rgbDataDst = static_cast<uint32_t*>(mDestImage.data); + uint32_t* rgbDataSrc = static_cast<uint32_t*>(mRawRgba8888Image.planes[UHDR_PLANE_PACKED]); + uint32_t* rgbDataDst = static_cast<uint32_t*>(mDestImage.planes[UHDR_PLANE_PACKED]); if (rgbDataSrc == nullptr || rgbDataDst == nullptr) { std::cerr << "invalid src or dst pointer for psnr computation " << std::endl; return; } uint64_t rSqError = 0, gSqError = 0, bSqError = 0; - for (size_t i = 0; i < mRawYuv420Image.width * mRawYuv420Image.height; i++) { + for (size_t i = 0; i < mRawYuv420Image.w * mRawYuv420Image.h; i++) { int rSrc = *rgbDataSrc & 0xff; int rDst = *rgbDataDst & 0xff; rSqError += (rSrc - rDst) * (rSrc - rDst); @@ -702,13 +923,13 @@ void UltraHdrAppInput::computeRGBSdrPSNR() { rgbDataSrc++; rgbDataDst++; } - double meanSquareError = (double)rSqError / (mRawYuv420Image.width * mRawYuv420Image.height); + double meanSquareError = (double)rSqError / (mRawYuv420Image.w * mRawYuv420Image.h); mPsnr[0] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100; - meanSquareError = (double)gSqError / (mRawYuv420Image.width * mRawYuv420Image.height); + meanSquareError = (double)gSqError / (mRawYuv420Image.w * mRawYuv420Image.h); mPsnr[1] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100; - meanSquareError = (double)bSqError / (mRawYuv420Image.width * mRawYuv420Image.height); + meanSquareError = (double)bSqError / (mRawYuv420Image.w * mRawYuv420Image.h); mPsnr[2] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100; std::cout << "psnr r :: " << mPsnr[0] << " psnr g :: " << mPsnr[1] << " psnr b :: " << mPsnr[2] @@ -716,68 +937,67 @@ void UltraHdrAppInput::computeRGBSdrPSNR() { } void UltraHdrAppInput::computeYUVHdrPSNR() { - if (mOf == ULTRAHDR_OUTPUT_SDR || mOf == ULTRAHDR_OUTPUT_HDR_LINEAR) { - std::cout << "psnr not supported for output format " << mOf << std::endl; + if (mOfmt != UHDR_IMG_FMT_32bppRGBA1010102) { + std::cout << "psnr not supported for output format " << mOfmt << std::endl; return; } - uint16_t* yuvDataSrc = static_cast<uint16_t*>(mRawP010Image.data); - uint16_t* yuvDataDst = static_cast<uint16_t*>(mDestYUV444Image.data); - if (yuvDataSrc == nullptr || yuvDataDst == nullptr) { + uint16_t* yDataSrc = static_cast<uint16_t*>(mRawP010Image.planes[UHDR_PLANE_Y]); + uint16_t* uDataSrc = static_cast<uint16_t*>(mRawP010Image.planes[UHDR_PLANE_UV]); + uint16_t* vDataSrc = uDataSrc + 1; + + uint16_t* yDataDst = static_cast<uint16_t*>(mDestYUV444Image.planes[UHDR_PLANE_Y]); + uint16_t* uDataDst = static_cast<uint16_t*>(mDestYUV444Image.planes[UHDR_PLANE_U]); + uint16_t* vDataDst = static_cast<uint16_t*>(mDestYUV444Image.planes[UHDR_PLANE_V]); + if (yDataSrc == nullptr || uDataSrc == nullptr || yDataDst == nullptr || uDataDst == nullptr || + vDataDst == nullptr) { std::cerr << "invalid src or dst pointer for psnr computation " << std::endl; return; } - if ((mOf == ULTRAHDR_OUTPUT_HDR_PQ && mTf != ULTRAHDR_TF_PQ) || - (mOf == ULTRAHDR_OUTPUT_HDR_HLG && mTf != ULTRAHDR_TF_HLG)) { + if (mOTf != mP010Tf) { std::cout << "input transfer function and output format are not compatible, psnr results " "may be unreliable" << std::endl; } - uint16_t* yDataSrc = static_cast<uint16_t*>(mRawP010Image.data); - uint16_t* uDataSrc = yDataSrc + (mRawP010Image.width * mRawP010Image.height); - uint16_t* vDataSrc = uDataSrc + 1; - - uint16_t* yDataDst = static_cast<uint16_t*>(mDestYUV444Image.data); - uint16_t* uDataDst = yDataDst + (mDestYUV444Image.width * mDestYUV444Image.height); - uint16_t* vDataDst = uDataDst + (mDestYUV444Image.width * mDestYUV444Image.height); - uint64_t ySqError = 0, uSqError = 0, vSqError = 0; - for (size_t i = 0; i < mDestYUV444Image.height; i++) { - for (size_t j = 0; j < mDestYUV444Image.width; j++) { - int ySrc = (yDataSrc[mRawP010Image.width * i + j] >> 6) & 0x3ff; + for (size_t i = 0; i < mDestYUV444Image.h; i++) { + for (size_t j = 0; j < mDestYUV444Image.w; j++) { + int ySrc = (yDataSrc[mRawP010Image.stride[UHDR_PLANE_Y] * i + j] >> 6) & 0x3ff; ySrc = CLIP3(ySrc, 64, 940); - int yDst = yDataDst[mDestYUV444Image.width * i + j] & 0x3ff; + int yDst = yDataDst[mDestYUV444Image.stride[UHDR_PLANE_Y] * i + j] & 0x3ff; ySqError += (ySrc - yDst) * (ySrc - yDst); if (i % 2 == 0 && j % 2 == 0) { - int uSrc = (uDataSrc[mRawP010Image.width * (i / 2) + (j / 2) * 2] >> 6) & 0x3ff; + int uSrc = + (uDataSrc[mRawP010Image.stride[UHDR_PLANE_UV] * (i / 2) + (j / 2) * 2] >> 6) & 0x3ff; uSrc = CLIP3(uSrc, 64, 960); - int uDst = uDataDst[mDestYUV444Image.width * i + j] & 0x3ff; - uDst += uDataDst[mDestYUV444Image.width * i + j + 1] & 0x3ff; - uDst += uDataDst[mDestYUV444Image.width * (i + 1) + j + 1] & 0x3ff; - uDst += uDataDst[mDestYUV444Image.width * (i + 1) + j + 1] & 0x3ff; + int uDst = uDataDst[mDestYUV444Image.stride[UHDR_PLANE_U] * i + j] & 0x3ff; + uDst += uDataDst[mDestYUV444Image.stride[UHDR_PLANE_U] * i + j + 1] & 0x3ff; + uDst += uDataDst[mDestYUV444Image.stride[UHDR_PLANE_U] * (i + 1) + j + 1] & 0x3ff; + uDst += uDataDst[mDestYUV444Image.stride[UHDR_PLANE_U] * (i + 1) + j + 1] & 0x3ff; uDst = (uDst + 2) >> 2; uSqError += (uSrc - uDst) * (uSrc - uDst); - int vSrc = (vDataSrc[mRawP010Image.width * (i / 2) + (j / 2) * 2] >> 6) & 0x3ff; + int vSrc = + (vDataSrc[mRawP010Image.stride[UHDR_PLANE_UV] * (i / 2) + (j / 2) * 2] >> 6) & 0x3ff; vSrc = CLIP3(vSrc, 64, 960); - int vDst = vDataDst[mDestYUV444Image.width * i + j] & 0x3ff; - vDst += vDataDst[mDestYUV444Image.width * i + j + 1] & 0x3ff; - vDst += vDataDst[mDestYUV444Image.width * (i + 1) + j + 1] & 0x3ff; - vDst += vDataDst[mDestYUV444Image.width * (i + 1) + j + 1] & 0x3ff; + int vDst = vDataDst[mDestYUV444Image.stride[UHDR_PLANE_V] * i + j] & 0x3ff; + vDst += vDataDst[mDestYUV444Image.stride[UHDR_PLANE_V] * i + j + 1] & 0x3ff; + vDst += vDataDst[mDestYUV444Image.stride[UHDR_PLANE_V] * (i + 1) + j + 1] & 0x3ff; + vDst += vDataDst[mDestYUV444Image.stride[UHDR_PLANE_V] * (i + 1) + j + 1] & 0x3ff; vDst = (vDst + 2) >> 2; vSqError += (vSrc - vDst) * (vSrc - vDst); } } } - double meanSquareError = (double)ySqError / (mDestYUV444Image.width * mDestYUV444Image.height); + double meanSquareError = (double)ySqError / (mDestYUV444Image.w * mDestYUV444Image.h); mPsnr[0] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100; - meanSquareError = (double)uSqError / (mDestYUV444Image.width * mDestYUV444Image.height / 4); + meanSquareError = (double)uSqError / (mDestYUV444Image.w * mDestYUV444Image.h / 4); mPsnr[1] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100; - meanSquareError = (double)vSqError / (mDestYUV444Image.width * mDestYUV444Image.height / 4); + meanSquareError = (double)vSqError / (mDestYUV444Image.w * mDestYUV444Image.h / 4); mPsnr[2] = meanSquareError ? 10 * log10((double)1023 * 1023 / meanSquareError) : 100; std::cout << "psnr y :: " << mPsnr[0] << " psnr u :: " << mPsnr[1] << " psnr v :: " << mPsnr[2] @@ -785,52 +1005,52 @@ void UltraHdrAppInput::computeYUVHdrPSNR() { } void UltraHdrAppInput::computeYUVSdrPSNR() { - if (mOf != ULTRAHDR_OUTPUT_SDR) { - std::cout << "psnr not supported for output format " << mOf << std::endl; + if (mOfmt != UHDR_IMG_FMT_32bppRGBA8888) { + std::cout << "psnr not supported for output format " << mOfmt << std::endl; return; } - uint8_t* yDataSrc = static_cast<uint8_t*>(mRawYuv420Image.data); - uint8_t* uDataSrc = yDataSrc + (mRawYuv420Image.width * mRawYuv420Image.height); - uint8_t* vDataSrc = uDataSrc + (mRawYuv420Image.width * mRawYuv420Image.height / 4); + uint8_t* yDataSrc = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_Y]); + uint8_t* uDataSrc = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_U]); + uint8_t* vDataSrc = static_cast<uint8_t*>(mRawYuv420Image.planes[UHDR_PLANE_V]); - uint8_t* yDataDst = static_cast<uint8_t*>(mDestYUV444Image.data); - uint8_t* uDataDst = yDataDst + (mDestYUV444Image.width * mDestYUV444Image.height); - uint8_t* vDataDst = uDataDst + (mDestYUV444Image.width * mDestYUV444Image.height); + uint8_t* yDataDst = static_cast<uint8_t*>(mDestYUV444Image.planes[UHDR_PLANE_Y]); + uint8_t* uDataDst = static_cast<uint8_t*>(mDestYUV444Image.planes[UHDR_PLANE_U]); + uint8_t* vDataDst = static_cast<uint8_t*>(mDestYUV444Image.planes[UHDR_PLANE_V]); uint64_t ySqError = 0, uSqError = 0, vSqError = 0; - for (size_t i = 0; i < mDestYUV444Image.height; i++) { - for (size_t j = 0; j < mDestYUV444Image.width; j++) { - int ySrc = yDataSrc[mRawYuv420Image.width * i + j]; - int yDst = yDataDst[mDestYUV444Image.width * i + j]; + for (size_t i = 0; i < mDestYUV444Image.h; i++) { + for (size_t j = 0; j < mDestYUV444Image.w; j++) { + int ySrc = yDataSrc[mRawYuv420Image.stride[UHDR_PLANE_Y] * i + j]; + int yDst = yDataDst[mDestYUV444Image.stride[UHDR_PLANE_Y] * i + j]; ySqError += (ySrc - yDst) * (ySrc - yDst); if (i % 2 == 0 && j % 2 == 0) { - int uSrc = uDataSrc[mRawYuv420Image.width / 2 * (i / 2) + j / 2]; - int uDst = uDataDst[mDestYUV444Image.width * i + j]; - uDst += uDataDst[mDestYUV444Image.width * i + j + 1]; - uDst += uDataDst[mDestYUV444Image.width * (i + 1) + j]; - uDst += uDataDst[mDestYUV444Image.width * (i + 1) + j + 1]; + int uSrc = uDataSrc[mRawYuv420Image.stride[UHDR_PLANE_U] * (i / 2) + j / 2]; + int uDst = uDataDst[mDestYUV444Image.stride[UHDR_PLANE_U] * i + j]; + uDst += uDataDst[mDestYUV444Image.stride[UHDR_PLANE_U] * i + j + 1]; + uDst += uDataDst[mDestYUV444Image.stride[UHDR_PLANE_U] * (i + 1) + j]; + uDst += uDataDst[mDestYUV444Image.stride[UHDR_PLANE_U] * (i + 1) + j + 1]; uDst = (uDst + 2) >> 2; uSqError += (uSrc - uDst) * (uSrc - uDst); - int vSrc = vDataSrc[mRawYuv420Image.width / 2 * (i / 2) + j / 2]; - int vDst = vDataDst[mDestYUV444Image.width * i + j]; - vDst += vDataDst[mDestYUV444Image.width * i + j + 1]; - vDst += vDataDst[mDestYUV444Image.width * (i + 1) + j]; - vDst += vDataDst[mDestYUV444Image.width * (i + 1) + j + 1]; + int vSrc = vDataSrc[mRawYuv420Image.stride[UHDR_PLANE_V] * (i / 2) + j / 2]; + int vDst = vDataDst[mDestYUV444Image.stride[UHDR_PLANE_V] * i + j]; + vDst += vDataDst[mDestYUV444Image.stride[UHDR_PLANE_V] * i + j + 1]; + vDst += vDataDst[mDestYUV444Image.stride[UHDR_PLANE_V] * (i + 1) + j]; + vDst += vDataDst[mDestYUV444Image.stride[UHDR_PLANE_V] * (i + 1) + j + 1]; vDst = (vDst + 2) >> 2; vSqError += (vSrc - vDst) * (vSrc - vDst); } } } - double meanSquareError = (double)ySqError / (mDestYUV444Image.width * mDestYUV444Image.height); + double meanSquareError = (double)ySqError / (mDestYUV444Image.w * mDestYUV444Image.h); mPsnr[0] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100; - meanSquareError = (double)uSqError / (mDestYUV444Image.width * mDestYUV444Image.height / 4); + meanSquareError = (double)uSqError / (mDestYUV444Image.w * mDestYUV444Image.h / 4); mPsnr[1] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100; - meanSquareError = (double)vSqError / (mDestYUV444Image.width * mDestYUV444Image.height / 4); + meanSquareError = (double)vSqError / (mDestYUV444Image.w * mDestYUV444Image.h / 4); mPsnr[2] = meanSquareError ? 10 * log10((double)255 * 255 / meanSquareError) : 100; std::cout << "psnr y :: " << mPsnr[0] << " psnr u:: " << mPsnr[1] << " psnr v :: " << mPsnr[2] @@ -841,16 +1061,18 @@ static void usage(const char* name) { fprintf(stderr, "\n## ultra hdr demo application.\nUsage : %s \n", name); fprintf(stderr, " -m mode of operation. [0:encode, 1:decode] \n"); fprintf(stderr, "\n## encoder options : \n"); - fprintf(stderr, " -p raw 10 bit input resource in p010 color format, mandatory. \n"); + fprintf(stderr, " -p raw 10 bit input resource in p010 color format. \n"); fprintf(stderr, " -y raw 8 bit input resource in yuv420, optional. \n" " if not provided tonemapping happens internally. \n"); - fprintf(stderr, " -i compressed 8 bit jpeg file path, optional \n"); - fprintf(stderr, " -w input file width, mandatory. \n"); - fprintf(stderr, " -h input file height, mandatory. \n"); + fprintf(stderr, " -i compressed 8 bit jpeg file path. \n"); + fprintf(stderr, " -g compressed 8 bit gainmap file path. \n"); + fprintf(stderr, " -f gainmap metadata config file. \n"); + fprintf(stderr, " -w input file width. \n"); + fprintf(stderr, " -h input file height. \n"); fprintf(stderr, " -C 10 bit input color gamut, optional. [0:bt709, 1:p3, 2:bt2100] \n"); fprintf(stderr, " -c 8 bit input color gamut, optional. [0:bt709, 1:p3, 2:bt2100] \n"); - fprintf(stderr, " -t input transfer function, optional. [0:linear, 1:hlg, 2:pq] \n"); + fprintf(stderr, " -t 10 bit input transfer function, optional. [0:linear, 1:hlg, 2:pq] \n"); fprintf(stderr, " -q quality factor to be used while encoding 8 bit image, optional. [0-100].\n" " gain map image does not use this quality factor. \n" @@ -859,22 +1081,23 @@ static void usage(const char* name) { fprintf(stderr, "\n## decoder options : \n"); fprintf(stderr, " -j ultra hdr input resource, mandatory in decode mode. \n"); fprintf(stderr, - " -o output transfer function, optional. [0:sdr, 1:hdr_linear, 2:hdr_pq, " - "3:hdr_hlg] \n"); + " -o output transfer function, optional. [0:linear, 1:hlg, 2:pq, 3:srgb] \n"); + fprintf(stderr, + " -O output color format, optional. [3:rgba8888, 4:rgbahalffloat, 5:rgba1010102] \n" + "It should be noted that not all combinations of output color format and output transfer " + "function are supported. srgb output color transfer shall be paired with rgba8888 only. " + "hlg, pq shall be paired with rgba1010102. linear shall be paired with rgbahalffloat"); fprintf(stderr, "\n## examples of usage :\n"); fprintf(stderr, "\n## encode api-0 :\n"); fprintf(stderr, " ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -w 1920 -h 1080 -q 97\n"); fprintf(stderr, - " ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -w 1920 -h 1080 -q 97 -C 2 -t 2\n"); + " ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -w 1920 -h 1080 -q 97 -C 1 -t 2\n"); fprintf(stderr, "\n## encode api-1 :\n"); fprintf(stderr, " ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 " "-h 1080 -q 97\n"); fprintf(stderr, " ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 " - "-h 1080 -q 97\n"); - fprintf(stderr, - " ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 " "-h 1080 -q 97 -C 2 -c 1 -t 1\n"); fprintf(stderr, " ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 " @@ -882,27 +1105,34 @@ static void usage(const char* name) { fprintf(stderr, "\n## encode api-2 :\n"); fprintf(stderr, " ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -i " - "cosmat_1920x1080_420_8bit.jpg -w 1920 -h 1080 -t 1 -o 3 -e 1\n"); + "cosmat_1920x1080_420_8bit.jpg -w 1920 -h 1080 -t 1 -o 3 -O 3 -e 1\n"); fprintf(stderr, "\n## encode api-3 :\n"); fprintf(stderr, " ultrahdr_app -m 0 -p cosmat_1920x1080_p010.yuv -i cosmat_1920x1080_420_8bit.jpg -w " - "1920 -h 1080 -t 1 -o 3 -e 1\n"); + "1920 -h 1080 -t 1 -o 1 -O 5 -e 1\n"); + fprintf(stderr, "\n## encode api-4 :\n"); + fprintf(stderr, + " ultrahdr_app -m 0 -i cosmat_1920x1080_420_8bit.jpg -g cosmat_1920x1080_420_8bit.jpg " + "-f metadata.cfg\n"); fprintf(stderr, "\n## decode api :\n"); fprintf(stderr, " ultrahdr_app -m 1 -j cosmat_1920x1080_hdr.jpg \n"); - fprintf(stderr, " ultrahdr_app -m 1 -j cosmat_1920x1080_hdr.jpg -o 2\n"); + fprintf(stderr, " ultrahdr_app -m 1 -j cosmat_1920x1080_hdr.jpg -o 3 -O 3\n"); + fprintf(stderr, " ultrahdr_app -m 1 -j cosmat_1920x1080_hdr.jpg -o 1 -O 5\n"); fprintf(stderr, "\n"); } int main(int argc, char* argv[]) { - char opt_string[] = "p:y:i:w:h:C:c:t:q:o:m:j:e:"; + char opt_string[] = "p:y:i:g:f:w:h:C:c:t:q:o:O:m:j:e:"; char *p010_file = nullptr, *yuv420_file = nullptr, *jpegr_file = nullptr, - *yuv420_jpeg_file = nullptr; + *yuv420_jpeg_file = nullptr, *gainmap_jpeg_file = nullptr, + *gainmap_metadata_cfg_file = nullptr; int width = 0, height = 0; - ultrahdr_color_gamut p010Cg = ULTRAHDR_COLORGAMUT_BT709; - ultrahdr_color_gamut yuv420Cg = ULTRAHDR_COLORGAMUT_BT709; - ultrahdr_transfer_function tf = ULTRAHDR_TF_HLG; + uhdr_color_gamut_t p010Cg = UHDR_CG_BT_709; + uhdr_color_gamut_t yuv420Cg = UHDR_CG_BT_709; + uhdr_color_transfer_t p010Tf = UHDR_CT_HLG; int quality = 100; - ultrahdr_output_format of = ULTRAHDR_OUTPUT_HDR_HLG; + uhdr_color_transfer_t outTf = UHDR_CT_HLG; + uhdr_img_fmt_t outFmt = UHDR_IMG_FMT_32bppRGBA1010102; int mode = 0; int compute_psnr = 0; int ch; @@ -917,6 +1147,12 @@ int main(int argc, char* argv[]) { case 'i': yuv420_jpeg_file = optarg_s; break; + case 'g': + gainmap_jpeg_file = optarg_s; + break; + case 'f': + gainmap_metadata_cfg_file = optarg_s; + break; case 'w': width = atoi(optarg_s); break; @@ -924,19 +1160,22 @@ int main(int argc, char* argv[]) { height = atoi(optarg_s); break; case 'C': - p010Cg = static_cast<ultrahdr_color_gamut>(atoi(optarg_s)); + p010Cg = static_cast<uhdr_color_gamut_t>(atoi(optarg_s)); break; case 'c': - yuv420Cg = static_cast<ultrahdr_color_gamut>(atoi(optarg_s)); + yuv420Cg = static_cast<uhdr_color_gamut_t>(atoi(optarg_s)); break; case 't': - tf = static_cast<ultrahdr_transfer_function>(atoi(optarg_s)); + p010Tf = static_cast<uhdr_color_transfer_t>(atoi(optarg_s)); break; case 'q': quality = atoi(optarg_s); break; + case 'O': + outFmt = static_cast<uhdr_img_fmt_t>(atoi(optarg_s)); + break; case 'o': - of = static_cast<ultrahdr_output_format>(atoi(optarg_s)); + outTf = static_cast<uhdr_color_transfer_t>(atoi(optarg_s)); break; case 'm': mode = atoi(optarg_s); @@ -953,25 +1192,30 @@ int main(int argc, char* argv[]) { } } if (mode == 0) { - if (width <= 0 || height <= 0 || p010_file == nullptr) { + if ((width <= 0 || height <= 0 || p010_file == nullptr) && + (yuv420_jpeg_file == nullptr || gainmap_jpeg_file == nullptr || + gainmap_metadata_cfg_file == nullptr)) { usage(argv[0]); return -1; } - UltraHdrAppInput appInput(p010_file, yuv420_file, yuv420_jpeg_file, width, height, p010Cg, - yuv420Cg, tf, quality, of); + UltraHdrAppInput appInput(p010_file, yuv420_file, yuv420_jpeg_file, gainmap_jpeg_file, + gainmap_metadata_cfg_file, width, height, p010Cg, yuv420Cg, p010Tf, + quality, outTf, outFmt); if (!appInput.encode()) return -1; if (compute_psnr == 1) { if (!appInput.decode()) return -1; - if (of == ULTRAHDR_OUTPUT_SDR && yuv420_file != nullptr) { + if (outFmt == UHDR_IMG_FMT_32bppRGBA8888 && yuv420_file != nullptr) { appInput.convertYuv420ToRGBImage(); appInput.computeRGBSdrPSNR(); appInput.convertRgba8888ToYUV444Image(); appInput.computeYUVSdrPSNR(); - } else if (of == ULTRAHDR_OUTPUT_HDR_HLG || of == ULTRAHDR_OUTPUT_HDR_PQ) { + } else if (outFmt == UHDR_IMG_FMT_32bppRGBA1010102 && p010_file != nullptr) { appInput.convertP010ToRGBImage(); appInput.computeRGBHdrPSNR(); appInput.convertRgba1010102ToYUV444Image(); appInput.computeYUVHdrPSNR(); + } else { + std::cerr << "failed to compute psnr " << std::endl; } } } else if (mode == 1) { @@ -979,7 +1223,7 @@ int main(int argc, char* argv[]) { usage(argv[0]); return -1; } - UltraHdrAppInput appInput(jpegr_file, of); + UltraHdrAppInput appInput(jpegr_file, outTf, outFmt); if (!appInput.decode()) return -1; } else { std::cerr << "unrecognized input mode " << mode << std::endl; |