From d4fa59c473584ba9a5ee7de861d093a464896ca0 Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Wed, 1 Nov 2023 02:46:57 +0530 Subject: add support for building on windows platform --- CMakeLists.txt | 128 ++++++++++++------ README.md | 65 +++++++-- examples/ultrahdr_app.cpp | 96 ++++++++++--- fuzzer/README.md | 4 +- lib/jpegr.cpp | 150 +++++++++++---------- tests/jpegdecoderhelper_test.cpp | 37 ++--- tests/jpegencoderhelper_test.cpp | 37 ++--- tests/jpegr_test.cpp | 45 +++++-- .../image_io/includes/image_io/base/data_range.h | 4 +- third_party/image_io/src/utils/file_utils.cc | 6 +- 10 files changed, 365 insertions(+), 207 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09ba3e5..86f378a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ project(UltraHdr C CXX) # Detect system ########################################################### if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") +elseif(WIN32) elseif(APPLE) else() message(FATAL_ERROR "Platform not supported") @@ -61,9 +62,12 @@ endif() ########################################################### # Options ########################################################### -if(NOT CMAKE_BUILD_TYPE) - message(STATUS "No build type chosen, selecting Release") - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "The type of build: Debug Release MinSizeRel RelWithDebInfo." FORCE) +get_cmake_property(IS_MULTI GENERATOR_IS_MULTI_CONFIG) +if (NOT IS_MULTI) + if (NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type chosen, selecting Release") + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "The type of build: Debug Release MinSizeRel RelWithDebInfo." FORCE) + endif() endif() function(option_if_not_defined name description default) @@ -84,39 +88,61 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -add_compile_options(-ffunction-sections) -add_compile_options(-fdata-sections) -add_compile_options(-fomit-frame-pointer) -if(ARCH STREQUAL "x86") - add_compile_options(-m32) - add_compile_options(-march=pentium4) - add_compile_options(-mtune=generic) -endif() -if(ARCH STREQUAL "x86_64") - add_compile_options(-m64) - add_compile_options(-march=x86-64) - add_compile_options(-mtune=generic) -endif() - -include(CheckCXXCompilerFlag) -function(CheckCompilerOption opt res) - set(CMAKE_REQUIRED_FLAGS ${opt}) - check_cxx_compiler_flag(${opt} ${res}) - unset(CMAKE_REQUIRED_FLAGS) - if(NOT ${res}) - message(FATAL_ERROR "Unsupported compiler option(s) ${opt}") +if(MSVC) + if(DEFINED UHDR_SANITIZE_OPTIONS) + message(FATAL_ERROR "Building with Sanitizer options not supported in MSVC path") + endif() + if(UHDR_BUILD_FUZZERS) + message(FATAL_ERROR "Building fuzzers not supported in MSVC path") + endif() + add_compile_options($<$:/MT> + $<$:/MTd> + $<$:/MT> + $<$:/MT> + $<$:/MT>) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + # Disable specific warnings + # TODO: None of these should be disabled, but for now,for a warning-free msvc build these are + # added. fix the warnings and remove these filters + add_compile_options(/wd4244) # conversion from 'type1' to 'type2', possible loss of data + add_compile_options(/wd4267) # conversion from 'size_t' to 'type' possible loss of data + add_compile_options(/wd4305) # truncation from 'double' to 'float' + add_compile_options(/wd4838) # conversion from 'type1' to 'type2' requires a narrowing conversion +else() + add_compile_options(-ffunction-sections) + add_compile_options(-fdata-sections) + add_compile_options(-fomit-frame-pointer) + if(ARCH STREQUAL "x86") + add_compile_options(-m32) + add_compile_options(-march=pentium4) + add_compile_options(-mtune=generic) + endif() + if(ARCH STREQUAL "x86_64") + add_compile_options(-m64) + add_compile_options(-march=x86-64) + add_compile_options(-mtune=generic) endif() -endfunction(CheckCompilerOption) -if(DEFINED UHDR_SANITIZE_OPTIONS) - CheckCompilerOption("-fsanitize=${UHDR_SANITIZE_OPTIONS}" SUPPORTS_SAN_OPTIONS) - add_compile_options(-fsanitize=${UHDR_SANITIZE_OPTIONS}) - add_link_options(-fsanitize=${UHDR_SANITIZE_OPTIONS}) -endif() + include(CheckCXXCompilerFlag) + function(CheckCompilerOption opt res) + set(CMAKE_REQUIRED_FLAGS ${opt}) + check_cxx_compiler_flag(${opt} ${res}) + unset(CMAKE_REQUIRED_FLAGS) + if(NOT ${res}) + message(FATAL_ERROR "Unsupported compiler option(s) ${opt}") + endif() + endfunction(CheckCompilerOption) -if(UHDR_BUILD_FUZZERS) - CheckCompilerOption("-fsanitize=fuzzer-no-link" fuzz) - add_compile_options(-fsanitize=fuzzer-no-link) + if(DEFINED UHDR_SANITIZE_OPTIONS) + CheckCompilerOption("-fsanitize=${UHDR_SANITIZE_OPTIONS}" SUPPORTS_SAN_OPTIONS) + add_compile_options(-fsanitize=${UHDR_SANITIZE_OPTIONS}) + add_link_options(-fsanitize=${UHDR_SANITIZE_OPTIONS}) + endif() + + if(UHDR_BUILD_FUZZERS) + CheckCompilerOption("-fsanitize=fuzzer-no-link" fuzz) + add_compile_options(-fsanitize=fuzzer-no-link) + endif() endif() if(UHDR_ENABLE_LOGS) @@ -148,7 +174,7 @@ ExternalProject_Add(libjpeg-turbo GIT_TAG 3.0.1 PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libjpeg-turbo SOURCE_DIR ${THIRD_PARTY_DIR}/libjpeg-turbo - BUILD_COMMAND ${CMAKE_COMMAND} --build --target jpeg-static + BUILD_COMMAND ${CMAKE_COMMAND} --build --config $ --target jpeg-static CMAKE_ARGS -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_FLAGS=${UHDR_CMAKE_C_FLAGS} @@ -157,8 +183,14 @@ ExternalProject_Add(libjpeg-turbo set(JPEG_INCLUDE_DIRS ${THIRD_PARTY_DIR}/libjpeg-turbo/ ${CMAKE_CURRENT_BINARY_DIR}/libjpeg-turbo/src/libjpeg-turbo-build) -set(JPEG_LIBRARIES - ${CMAKE_CURRENT_BINARY_DIR}/libjpeg-turbo/src/libjpeg-turbo-build/libjpeg.a) + +if(IS_MULTI) + set(JPEG_LIBRARIES + ${CMAKE_CURRENT_BINARY_DIR}/libjpeg-turbo/src/libjpeg-turbo-build/$/jpeg-static.lib) +else() + set(JPEG_LIBRARIES + ${CMAKE_CURRENT_BINARY_DIR}/libjpeg-turbo/src/libjpeg-turbo-build/libjpeg.a) +endif() if(UHDR_BUILD_TESTS) # gtest and gmock @@ -177,9 +209,15 @@ if(UHDR_BUILD_TESTS) set(GTEST_INCLUDE_DIRS ${THIRD_PARTY_DIR}/googletest/googletest/include ${THIRD_PARTY_DIR}/googletest/googlemock/include) - set(GTEST_BOTH_LIBRARIES - ${CMAKE_CURRENT_BINARY_DIR}/googletest/src/googletest-build/lib/libgtest.a - ${CMAKE_CURRENT_BINARY_DIR}/googletest/src/googletest-build/lib/libgtest_main.a) + if(IS_MULTI) + set(GTEST_BOTH_LIBRARIES + ${CMAKE_CURRENT_BINARY_DIR}/googletest/src/googletest-build/lib/$/gtest.lib + ${CMAKE_CURRENT_BINARY_DIR}/googletest/src/googletest-build/lib/$/gtest_main.lib) + else() + set(GTEST_BOTH_LIBRARIES + ${CMAKE_CURRENT_BINARY_DIR}/googletest/src/googletest-build/lib/libgtest.a + ${CMAKE_CURRENT_BINARY_DIR}/googletest/src/googletest-build/lib/libgtest_main.a) + endif() endif() set_property(DIRECTORY PROPERTY ADDITIONAL_MAKE_CLEAN_FILES @@ -228,10 +266,14 @@ if(UHDR_BUILD_TESTS) target_link_options(ultrahdr_unit_test PRIVATE -fsanitize=fuzzer-no-link) endif() target_link_libraries(ultrahdr_unit_test ultrahdr ${GTEST_BOTH_LIBRARIES}) - execute_process(COMMAND cmake -E create_symlink - "${TESTS_DIR}/data/" - "${CMAKE_CURRENT_BINARY_DIR}/data" - ) + if(WIN32) + file(COPY "${TESTS_DIR}/data/" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/data") + else() + execute_process(COMMAND cmake -E create_symlink + "${TESTS_DIR}/data/" + "${CMAKE_CURRENT_BINARY_DIR}/data" + ) + endif() add_test(NAME UHDRUnitTests, COMMAND ultrahdr_unit_test) endif() diff --git a/README.md b/README.md index 07290f0..b7bc27b 100644 --- a/README.md +++ b/README.md @@ -23,33 +23,34 @@ For this libjpeg-turbo is used. This is cloned from and included in the build process. -### Requirements +Requirements +-------------- - [CMake](http://www.cmake.org) v3.13 or later - [NASM](http://www.nasm.us) or [Yasm](http://yasm.tortall.net) - (If libjpeg-turbo is building on x86 or x86-64 with SIMD extensions) + (If libjpeg-turbo needs to be built with SIMD extensions) * If using NASM, 2.13 or later is required. * If using Yasm, 1.2.0 or later is required. * If building on macOS, NASM or Yasm can be obtained from [MacPorts](http://www.macports.org/) or [Homebrew](http://brew.sh/). +- Compilers with support for C++17 + Should work with GCC v7 (or later) and Clang 5 (or later) on Linux and Mac Platforms. -### Building Lib and Samples +Should work with Microsoft Visual C++ 2019 (or later) on Windows Platforms. -To build libultrahdr and sample application: +Build Procedure +--------------- - mkdir {build_directory} - cd {build_directory} - cmake ../ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ - make +To build libultrahdr, examples, unit tests: -To build unit tests: +### Un*x (including Linux, Mac) mkdir {build_directory} cd {build_directory} - cmake ../ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUHDR_BUILD_TESTS=1 + cmake -G "Unix Makefiles" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DUHDR_BUILD_TESTS=1 ../ make ctest @@ -61,6 +62,50 @@ This will generate the following files under *{build_directory}*: **ultrahdr_unit_test**
Unit tests +### Visual C++ (IDE) + + mkdir {build_directory} + cd {build_directory} + cmake -G "Visual Studio 16 2019" -DUHDR_BUILD_TESTS=1 ../ + cmake --build ./ --config=Release + ctest -C Release + +This will generate the following files under *{build_directory/Release}*: + +**ultrahdr.lib**
Static link library for the ultrahdr API + +**ultrahdr_app.exe**
Sample application demonstrating ultrahdr API + +**ultrahdr_unit_test.exe**
Unit tests + +### MinGW + +NOTE: This assumes that you are building on a Windows machine using the MSYS +environment. + + mkdir {build_directory} + cd {build_directory} + cmake -G "MSYS Makefiles" -DUHDR_BUILD_TESTS=1 ../ + cmake --build ./ + ctest + + mkdir {build_directory} + cd {build_directory} + cmake -G "MinGW Makefiles" -DUHDR_BUILD_TESTS=1 ../ + cmake --build ./ + ctest + +This will generate the following files under *{build_directory}*: + +**libultrahdr.a**
Static link library for the ultrahdr API + +**ultrahdr_app.exe**
Sample application demonstrating ultrahdr API + +**ultrahdr_unit_test.exe**
Unit tests + + +NOTE: To not build unit tests, skip passing -DUHDR_BUILD_TESTS=1 + ### Building Fuzzers Refer to [README.md](fuzzer/README.md) for complete instructions. diff --git a/examples/ultrahdr_app.cpp b/examples/ultrahdr_app.cpp index 25170c9..f3fd372 100644 --- a/examples/ultrahdr_app.cpp +++ b/examples/ultrahdr_app.cpp @@ -14,8 +14,13 @@ * limitations under the License. */ +#ifdef _WIN32 +#include +#else #include -#include +#endif + +#include #include #include @@ -57,7 +62,60 @@ const float BT2020RGBtoYUVMatrix[9] = {0.2627, (-0.6780 / 1.4746), (-0.0593 / 1.4746)}; -//#define PROFILE_ENABLE 1 +int optind_s = 1; +int optopt_s = 0; +char* optarg_s = nullptr; + +int getopt_s(int argc, char* const argv[], char* ostr) { + if (optind_s >= argc) return -1; + + const char* arg = argv[optind_s]; + if (arg[0] != '-' || !arg[1]) { + std::cerr << "invalid option " << arg << std::endl; + return '?'; + } + optopt_s = arg[1]; + char* oindex = strchr(ostr, optopt_s); + if (!oindex) { + std::cerr << "unsupported option " << arg << std::endl; + return '?'; + } + if (oindex[1] != ':') { + optarg_s = nullptr; + return optopt_s; + } + + if (argc > ++optind_s) { + optarg_s = (char*)argv[optind_s++]; + } else { + std::cerr << "option " << arg << " requires an argument" << std::endl; + optarg_s = nullptr; + return '?'; + } + return optopt_s; +} + +// #define PROFILE_ENABLE 1 +#ifdef _WIN32 +class Profiler { + public: + void timerStart() { QueryPerformanceCounter(&mStartingTime); } + + void timerStop() { QueryPerformanceCounter(&mEndingTime); } + + int64_t elapsedTime() { + LARGE_INTEGER frequency; + LARGE_INTEGER elapsedMicroseconds; + QueryPerformanceFrequency(&frequency); + elapsedMicroseconds.QuadPart = mEndingTime.QuadPart - mStartingTime.QuadPart; + return (double)elapsedMicroseconds.QuadPart / (double)frequency.QuadPart * 1000000; + } + + private: + LARGE_INTEGER mStartingTime; + LARGE_INTEGER mEndingTime; +}; +#else class Profiler { public: void timerStart() { gettimeofday(&mStartingTime, nullptr); } @@ -75,6 +133,7 @@ class Profiler { struct timeval mStartingTime; struct timeval mEndingTime; }; +#endif static bool loadFile(const char* filename, void*& result, int length) { std::ifstream ifd(filename, std::ios::binary | std::ios::ate); @@ -247,8 +306,8 @@ bool UltraHdrAppInput::encode() { if (mYuv420File != nullptr && !fillYuv420ImageHandle()) return false; if (mYuv420JpegFile != nullptr && !fillYuv420JpegImageHandle()) return false; - mJpegImgR.maxLength = std::max(static_cast(8 * 1024) /* min size 8kb */, - mRawP010Image.width * mRawP010Image.height * 3 * 2); + mJpegImgR.maxLength = (std::max)(static_cast(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; @@ -835,6 +894,7 @@ static void usage(const char* name) { } int main(int argc, char* argv[]) { + char opt_string[] = "p:y:i:w:h:C:c:t:q:o:m:j:e:"; char *p010_file = nullptr, *yuv420_file = nullptr, *jpegr_file = nullptr, *yuv420_jpeg_file = nullptr; int width = 0, height = 0; @@ -846,46 +906,46 @@ int main(int argc, char* argv[]) { int mode = 0; int compute_psnr = 0; int ch; - while ((ch = getopt(argc, argv, "p:y:i:w:h:C:c:t:q:o:m:j:e:")) != -1) { + while ((ch = getopt_s(argc, argv, opt_string)) != -1) { switch (ch) { case 'p': - p010_file = optarg; + p010_file = optarg_s; break; case 'y': - yuv420_file = optarg; + yuv420_file = optarg_s; break; case 'i': - yuv420_jpeg_file = optarg; + yuv420_jpeg_file = optarg_s; break; case 'w': - width = atoi(optarg); + width = atoi(optarg_s); break; case 'h': - height = atoi(optarg); + height = atoi(optarg_s); break; case 'C': - p010Cg = static_cast(atoi(optarg)); + p010Cg = static_cast(atoi(optarg_s)); break; case 'c': - yuv420Cg = static_cast(atoi(optarg)); + yuv420Cg = static_cast(atoi(optarg_s)); break; case 't': - tf = static_cast(atoi(optarg)); + tf = static_cast(atoi(optarg_s)); break; case 'q': - quality = atoi(optarg); + quality = atoi(optarg_s); break; case 'o': - of = static_cast(atoi(optarg)); + of = static_cast(atoi(optarg_s)); break; case 'm': - mode = atoi(optarg); + mode = atoi(optarg_s); break; case 'j': - jpegr_file = optarg; + jpegr_file = optarg_s; break; case 'e': - compute_psnr = atoi(optarg); + compute_psnr = atoi(optarg_s); break; default: usage(argv[0]); diff --git a/fuzzer/README.md b/fuzzer/README.md index 48dc2d8..e48d859 100644 --- a/fuzzer/README.md +++ b/fuzzer/README.md @@ -3,9 +3,9 @@ Building fuzzers for libultrahdr ### Requirements -- [CMake](http://www.cmake.org) v3.13 or later +- Refer [Requirements](../README.md#Requirements) -- Compilers with support for options *-fsanitize=fuzzer, -fsanitize=fuzzer-no-link*. +- Additionally compilers are required to support options *-fsanitize=fuzzer, -fsanitize=fuzzer-no-link*. For instance, clang 12 (or later) ### Building Commands diff --git a/lib/jpegr.cpp b/lib/jpegr.cpp index 6fb8922..015ffce 100644 --- a/lib/jpegr.cpp +++ b/lib/jpegr.cpp @@ -14,7 +14,12 @@ * limitations under the License. */ +#ifdef _WIN32 +#include +#include +#else #include +#endif #include #include @@ -56,17 +61,22 @@ namespace ultrahdr { // JPEG compress quality (0 ~ 100) for gain map static const int kMapCompressQuality = 85; -#define CONFIG_MULTITHREAD 1 int GetCPUCoreCount() { int cpuCoreCount = 1; -#if CONFIG_MULTITHREAD -#if defined(_SC_NPROCESSORS_ONLN) + +#if defined(_WIN32) + SYSTEM_INFO system_info; + ZeroMemory(&system_info, sizeof(system_info)); + GetSystemInfo(&system_info); + cpuCoreCount = (size_t)system_info.dwNumberOfProcessors; +#elif defined(_SC_NPROCESSORS_ONLN) cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_SC_NPROCESSORS_CONF) + cpuCoreCount = sysconf(_SC_NPROCESSORS_CONF); #else - // _SC_NPROC_ONLN must be defined... - cpuCoreCount = sysconf(_SC_NPROC_ONLN); -#endif +#error platform-specific implementation for GetCPUCoreCount() missing. #endif + if (cpuCoreCount <= 0) cpuCoreCount = 1; return cpuCoreCount; } @@ -197,10 +207,7 @@ status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr, status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest, int quality, jr_exif_ptr exif) { // validate input arguments - if (auto ret = areInputArgumentsValid(p010_image_ptr, nullptr, hdr_tf, dest, quality); - ret != JPEGR_NO_ERROR) { - return ret; - } + JPEGR_CHECK(areInputArgumentsValid(p010_image_ptr, nullptr, hdr_tf, dest, quality)); if (exif != nullptr && exif->data == nullptr) { ALOGE("received nullptr for exif metadata"); return ERROR_JPEGR_BAD_PTR; @@ -218,13 +225,14 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfe const size_t yu420_luma_stride = ALIGNM(p010_image.width, JpegEncoderHelper::kCompressBatchSize); unique_ptr yuv420_image_data = make_unique(yu420_luma_stride * p010_image.height * 3 / 2); - jpegr_uncompressed_struct yuv420_image = {.data = yuv420_image_data.get(), - .width = p010_image.width, - .height = p010_image.height, - .colorGamut = p010_image.colorGamut, - .chroma_data = nullptr, - .luma_stride = yu420_luma_stride, - .chroma_stride = yu420_luma_stride >> 1}; + jpegr_uncompressed_struct yuv420_image; + yuv420_image.data = yuv420_image_data.get(); + yuv420_image.width = p010_image.width; + yuv420_image.height = p010_image.height; + yuv420_image.colorGamut = p010_image.colorGamut; + yuv420_image.chroma_data = nullptr; + yuv420_image.luma_stride = yu420_luma_stride; + yuv420_image.chroma_stride = yu420_luma_stride >> 1; uint8_t* data = reinterpret_cast(yuv420_image.data); yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height; @@ -232,7 +240,8 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfe JPEGR_CHECK(toneMap(&p010_image, &yuv420_image)); // gain map - ultrahdr_metadata_struct metadata = {.version = kJpegrVersion}; + ultrahdr_metadata_struct metadata; + metadata.version = kJpegrVersion; jpegr_uncompressed_struct gainmap_image; JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image)); std::unique_ptr map_data; @@ -241,11 +250,11 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfe // compress gain map JpegEncoderHelper jpeg_enc_obj_gm; JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm)); - jpegr_compressed_struct compressed_map = { - .data = jpeg_enc_obj_gm.getCompressedImagePtr(), - .length = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()), - .maxLength = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()), - .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + jpegr_compressed_struct compressed_map; + compressed_map.data = jpeg_enc_obj_gm.getCompressedImagePtr(); + compressed_map.length = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()); + compressed_map.maxLength = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()); + compressed_map.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; std::shared_ptr icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, yuv420_image.colorGamut); @@ -264,11 +273,11 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfe quality, icc->getData(), icc->getLength())) { return ERROR_JPEGR_ENCODE_ERROR; } - jpegr_compressed_struct jpeg = { - .data = jpeg_enc_obj_yuv420.getCompressedImagePtr(), - .length = static_cast(jpeg_enc_obj_yuv420.getCompressedImageSize()), - .maxLength = static_cast(jpeg_enc_obj_yuv420.getCompressedImageSize()), - .colorGamut = yuv420_image.colorGamut}; + jpegr_compressed_struct jpeg; + jpeg.data = jpeg_enc_obj_yuv420.getCompressedImagePtr(); + jpeg.length = static_cast(jpeg_enc_obj_yuv420.getCompressedImageSize()); + jpeg.maxLength = static_cast(jpeg_enc_obj_yuv420.getCompressedImageSize()); + jpeg.colorGamut = yuv420_image.colorGamut; // append gain map, no ICC since JPEG encode already did it JPEGR_CHECK(appendGainMap(&jpeg, &compressed_map, exif, /* icc */ nullptr, /* icc size */ 0, @@ -290,10 +299,7 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ALOGE("received nullptr for exif metadata"); return ERROR_JPEGR_BAD_PTR; } - if (auto ret = areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest, quality); - ret != JPEGR_NO_ERROR) { - return ret; - } + JPEGR_CHECK(areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest, quality)) // clean up input structure for later usage jpegr_uncompressed_struct p010_image = *p010_image_ptr; @@ -312,7 +318,8 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, } // gain map - ultrahdr_metadata_struct metadata = {.version = kJpegrVersion}; + ultrahdr_metadata_struct metadata; + metadata.version = kJpegrVersion; jpegr_uncompressed_struct gainmap_image; JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image)); std::unique_ptr map_data; @@ -321,11 +328,11 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, // compress gain map JpegEncoderHelper jpeg_enc_obj_gm; JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm)); - jpegr_compressed_struct compressed_map = { - .data = jpeg_enc_obj_gm.getCompressedImagePtr(), - .length = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()), - .maxLength = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()), - .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + jpegr_compressed_struct compressed_map; + compressed_map.data = jpeg_enc_obj_gm.getCompressedImagePtr(); + compressed_map.length = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()); + compressed_map.maxLength = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()); + compressed_map.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; std::shared_ptr icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, yuv420_image.colorGamut); @@ -403,11 +410,11 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, return ERROR_JPEGR_ENCODE_ERROR; } - jpegr_compressed_struct jpeg = { - .data = jpeg_enc_obj_yuv420.getCompressedImagePtr(), - .length = static_cast(jpeg_enc_obj_yuv420.getCompressedImageSize()), - .maxLength = static_cast(jpeg_enc_obj_yuv420.getCompressedImageSize()), - .colorGamut = yuv420_image.colorGamut}; + jpegr_compressed_struct jpeg; + jpeg.data = jpeg_enc_obj_yuv420.getCompressedImagePtr(); + jpeg.length = static_cast(jpeg_enc_obj_yuv420.getCompressedImageSize()); + jpeg.maxLength = static_cast(jpeg_enc_obj_yuv420.getCompressedImageSize()); + jpeg.colorGamut = yuv420_image.colorGamut; // append gain map, no ICC since JPEG encode already did it JPEGR_CHECK(appendGainMap(&jpeg, &compressed_map, exif, /* icc */ nullptr, /* icc size */ 0, @@ -429,10 +436,7 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ALOGE("received nullptr for compressed jpeg image"); return ERROR_JPEGR_BAD_PTR; } - if (auto ret = areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest); - ret != JPEGR_NO_ERROR) { - return ret; - } + JPEGR_CHECK(areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest)) // clean up input structure for later usage jpegr_uncompressed_struct p010_image = *p010_image_ptr; @@ -451,7 +455,8 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, } // gain map - ultrahdr_metadata_struct metadata = {.version = kJpegrVersion}; + ultrahdr_metadata_struct metadata; + metadata.version = kJpegrVersion; jpegr_uncompressed_struct gainmap_image; JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image)); std::unique_ptr map_data; @@ -460,11 +465,11 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, // compress gain map JpegEncoderHelper jpeg_enc_obj_gm; JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm)); - jpegr_compressed_struct gainmapjpg_image = { - .data = jpeg_enc_obj_gm.getCompressedImagePtr(), - .length = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()), - .maxLength = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()), - .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + jpegr_compressed_struct gainmapjpg_image; + gainmapjpg_image.data = jpeg_enc_obj_gm.getCompressedImagePtr(); + gainmapjpg_image.length = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()); + gainmapjpg_image.maxLength = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()); + gainmapjpg_image.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; return encodeJPEGR(yuv420jpg_image_ptr, &gainmapjpg_image, &metadata, dest); } @@ -478,10 +483,7 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ALOGE("received nullptr for compressed jpeg image"); return ERROR_JPEGR_BAD_PTR; } - if (auto ret = areInputArgumentsValid(p010_image_ptr, nullptr, hdr_tf, dest); - ret != JPEGR_NO_ERROR) { - return ret; - } + JPEGR_CHECK(areInputArgumentsValid(p010_image_ptr, nullptr, hdr_tf, dest)) // clean up input structure for later usage jpegr_uncompressed_struct p010_image = *p010_image_ptr; @@ -516,7 +518,8 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, } // gain map - ultrahdr_metadata_struct metadata = {.version = kJpegrVersion}; + ultrahdr_metadata_struct metadata; + metadata.version = kJpegrVersion; jpegr_uncompressed_struct gainmap_image; JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image, true /* sdr_is_601 */)); @@ -526,11 +529,11 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, // compress gain map JpegEncoderHelper jpeg_enc_obj_gm; JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm)); - jpegr_compressed_struct gainmapjpg_image = { - .data = jpeg_enc_obj_gm.getCompressedImagePtr(), - .length = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()), - .maxLength = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()), - .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + jpegr_compressed_struct gainmapjpg_image; + gainmapjpg_image.data = jpeg_enc_obj_gm.getCompressedImagePtr(); + gainmapjpg_image.length = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()); + gainmapjpg_image.maxLength = static_cast(jpeg_enc_obj_gm.getCompressedImageSize()); + gainmapjpg_image.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; return encodeJPEGR(yuv420jpg_image_ptr, &gainmapjpg_image, &metadata, dest); } @@ -923,7 +926,7 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr yuv420_image_ptr, return ERROR_JPEGR_INVALID_COLORGAMUT; } - const int threads = std::clamp(GetCPUCoreCount(), 1, 4); + const int threads = (std::min)(GetCPUCoreCount(), 4); size_t rowStep = threads == 1 ? image_height : kJobSzInRows; JobQueue jobQueue; @@ -967,7 +970,7 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr yuv420_image_ptr, rowStep = (threads == 1 ? image_height : kJobSzInRows) / kMapDimensionScaleFactor; for (size_t rowStart = 0; rowStart < map_height;) { - size_t rowEnd = std::min(rowStart + rowStep, map_height); + size_t rowEnd = (std::min)(rowStart + rowStep, map_height); jobQueue.enqueueJob(rowStart, rowEnd); rowStart = rowEnd; } @@ -1023,7 +1026,7 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, dest->width = yuv420_image_ptr->width; dest->height = yuv420_image_ptr->height; ShepardsIDW idwTable(kMapDimensionScaleFactor); - float display_boost = std::min(max_display_boost, metadata->maxContentBoost); + float display_boost = (std::min)(max_display_boost, metadata->maxContentBoost); GainLUT gainLUT(metadata, display_boost); JobQueue jobQueue; @@ -1102,14 +1105,14 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, } }; - const int threads = std::clamp(GetCPUCoreCount(), 1, 4); + const int threads = (std::min)(GetCPUCoreCount(), 4); std::vector workers; for (int th = 0; th < threads - 1; th++) { workers.push_back(std::thread(applyRecMap)); } const int rowStep = threads == 1 ? yuv420_image_ptr->height : kJobSzInRows; for (size_t rowStart = 0; rowStart < yuv420_image_ptr->height;) { - int rowEnd = std::min(rowStart + rowStep, yuv420_image_ptr->height); + int rowEnd = (std::min)(rowStart + rowStep, yuv420_image_ptr->height); jobQueue.enqueueJob(rowStart, rowEnd); rowStart = rowEnd; } @@ -1262,9 +1265,14 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, if (!decoder.extractEXIF(primary_jpg_image_ptr->data, primary_jpg_image_ptr->length)) { return ERROR_JPEGR_DECODE_ERROR; } - jpegr_exif_struct exif_from_jpg = {.data = nullptr, .length = 0}; - jpegr_compressed_struct new_jpg_image = { - .data = nullptr, .length = 0, .maxLength = 0, .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + jpegr_exif_struct exif_from_jpg; + exif_from_jpg.data = nullptr; + exif_from_jpg.length = 0; + jpegr_compressed_struct new_jpg_image; + new_jpg_image.data = nullptr; + new_jpg_image.length = 0; + new_jpg_image.maxLength = 0; + new_jpg_image.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; std::unique_ptr dest_data; if (decoder.getEXIFPos() >= 0) { if (pExif != nullptr) { diff --git a/tests/jpegdecoderhelper_test.cpp b/tests/jpegdecoderhelper_test.cpp index e811e37..3b8e88e 100644 --- a/tests/jpegdecoderhelper_test.cpp +++ b/tests/jpegdecoderhelper_test.cpp @@ -14,9 +14,11 @@ * limitations under the License. */ -#include #include +#include +#include + #include "ultrahdrcommon.h" #include "jpegdecoderhelper.h" #include "icc.h" @@ -60,32 +62,17 @@ JpegDecoderHelperTest::JpegDecoderHelperTest() {} JpegDecoderHelperTest::~JpegDecoderHelperTest() {} -static size_t getFileSize(int fd) { - struct stat st; - if (fstat(fd, &st) < 0) { - ALOGW("%s : fstat failed", __func__); - return 0; - } - return st.st_size; // bytes -} - static bool loadFile(const char filename[], JpegDecoderHelperTest::Image* result) { - int fd = open(filename, O_CLOEXEC); - if (fd < 0) { - return false; - } - int length = getFileSize(fd); - if (length == 0) { - close(fd); - return false; - } - result->buffer.reset(new uint8_t[length]); - if (read(fd, result->buffer.get(), length) != static_cast(length)) { - close(fd); - return false; + std::ifstream ifd(filename, std::ios::binary | std::ios::ate); + if (ifd.good()) { + int size = ifd.tellg(); + ifd.seekg(0, std::ios::beg); + result->buffer.reset(new uint8_t[size]); + ifd.read(reinterpret_cast(result->buffer.get()), size); + ifd.close(); + return true; } - close(fd); - return true; + return false; } void JpegDecoderHelperTest::SetUp() { diff --git a/tests/jpegencoderhelper_test.cpp b/tests/jpegencoderhelper_test.cpp index b1f0fea..3463c26 100644 --- a/tests/jpegencoderhelper_test.cpp +++ b/tests/jpegencoderhelper_test.cpp @@ -14,9 +14,11 @@ * limitations under the License. */ -#include #include +#include +#include + #include "ultrahdrcommon.h" #include "ultrahdr.h" #include "jpegencoderhelper.h" @@ -61,32 +63,17 @@ JpegEncoderHelperTest::JpegEncoderHelperTest() {} JpegEncoderHelperTest::~JpegEncoderHelperTest() {} -static size_t getFileSize(int fd) { - struct stat st; - if (fstat(fd, &st) < 0) { - ALOGW("%s : fstat failed", __func__); - return 0; - } - return st.st_size; // bytes -} - static bool loadFile(const char filename[], JpegEncoderHelperTest::Image* result) { - int fd = open(filename, O_CLOEXEC); - if (fd < 0) { - return false; - } - int length = getFileSize(fd); - if (length == 0) { - close(fd); - return false; - } - result->buffer.reset(new uint8_t[length]); - if (read(fd, result->buffer.get(), length) != static_cast(length)) { - close(fd); - return false; + std::ifstream ifd(filename, std::ios::binary | std::ios::ate); + if (ifd.good()) { + int size = ifd.tellg(); + ifd.seekg(0, std::ios::beg); + result->buffer.reset(new uint8_t[size]); + ifd.read(reinterpret_cast(result->buffer.get()), size); + ifd.close(); + return true; } - close(fd); - return true; + return false; } void JpegEncoderHelperTest::SetUp() { diff --git a/tests/jpegr_test.cpp b/tests/jpegr_test.cpp index 07977c2..bfbfcde 100644 --- a/tests/jpegr_test.cpp +++ b/tests/jpegr_test.cpp @@ -14,7 +14,11 @@ * limitations under the License. */ +#ifdef _WIN32 +#include +#else #include +#endif #include #include @@ -259,7 +263,7 @@ bool UhdrCompressedStructWrapper::allocateMemory() { std::cerr << "Object in bad state, mem alloc failed" << std::endl; return false; } - int maxLength = std::max(8 * 1024 /* min size 8kb */, (int)(mWidth * mHeight * 3 * 2)); + int maxLength = (std::max)(8 * 1024 /* min size 8kb */, (int)(mWidth * mHeight * 3 * 2)); mData = std::make_unique(maxLength); mImg.data = mData.get(); mImg.length = 0; @@ -1916,7 +1920,26 @@ INSTANTIATE_TEST_SUITE_P( // ============================================================================ // Profiling // ============================================================================ +#ifdef _WIN32 +class Profiler { + public: + void timerStart() { QueryPerformanceCounter(&mStartingTime); } + + void timerStop() { QueryPerformanceCounter(&mEndingTime); } + + int64_t elapsedTime() { + LARGE_INTEGER frequency; + LARGE_INTEGER elapsedMicroseconds; + QueryPerformanceFrequency(&frequency); + elapsedMicroseconds.QuadPart = mEndingTime.QuadPart - mStartingTime.QuadPart; + return (double)elapsedMicroseconds.QuadPart / (double)frequency.QuadPart * 1000000; + } + private: + LARGE_INTEGER mStartingTime; + LARGE_INTEGER mEndingTime; +}; +#else class Profiler { public: void timerStart() { gettimeofday(&mStartingTime, nullptr); } @@ -1934,6 +1957,7 @@ class Profiler { struct timeval mStartingTime; struct timeval mEndingTime; }; +#endif class JpegRBenchmark : public JpegR { public: @@ -1991,9 +2015,13 @@ TEST(JpegRTest, ProfileGainMapFuncs) { ASSERT_TRUE(rawImg420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); ASSERT_TRUE(rawImg420.allocateMemory()); ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName)); - ultrahdr_metadata_struct metadata = {.version = "1.0"}; - jpegr_uncompressed_struct map = { - .data = NULL, .width = 0, .height = 0, .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + ultrahdr_metadata_struct metadata; + metadata.version = kJpegrVersion; + jpegr_uncompressed_struct map; + map.data = NULL; + map.width = 0; + map.height = 0; + map.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; { auto rawImg = rawImgP010.getImageHandle(); if (rawImg->luma_stride == 0) rawImg->luma_stride = rawImg->width; @@ -2019,10 +2047,11 @@ TEST(JpegRTest, ProfileGainMapFuncs) { const int dstSize = kImageWidth * kImageWidth * 4; auto bufferDst = std::make_unique(dstSize); - jpegr_uncompressed_struct dest = {.data = bufferDst.get(), - .width = 0, - .height = 0, - .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + jpegr_uncompressed_struct dest; + dest.data = bufferDst.get(); + dest.width = 0; + dest.height = 0; + dest.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; ASSERT_NO_FATAL_FAILURE( benchmark.BenchmarkApplyGainMap(rawImg420.getImageHandle(), &map, &metadata, &dest)); diff --git a/third_party/image_io/includes/image_io/base/data_range.h b/third_party/image_io/includes/image_io/base/data_range.h index e2e339a..c7404ff 100644 --- a/third_party/image_io/includes/image_io/base/data_range.h +++ b/third_party/image_io/includes/image_io/base/data_range.h @@ -59,8 +59,8 @@ class DataRange { /// @return The DataRange that represents the intersection, or one that is /// is invalid if the ranges do not overlap at all. DataRange GetIntersection(const DataRange& data_range) const { - return DataRange(std::max(data_range.begin_, begin_), - std::min(data_range.end_, end_)); + return DataRange((std::max)(data_range.begin_, begin_), + (std::min)(data_range.end_, end_)); } /// @param rhs A DataRange to compare with this one. diff --git a/third_party/image_io/src/utils/file_utils.cc b/third_party/image_io/src/utils/file_utils.cc index 626d537..8156d50 100644 --- a/third_party/image_io/src/utils/file_utils.cc +++ b/third_party/image_io/src/utils/file_utils.cc @@ -1,9 +1,9 @@ #include "image_io/utils/file_utils.h" #include -#import -#import -#import +#include +#include +#include #include "image_io/base/data_range.h" -- cgit v1.2.3