diff options
| -rw-r--r-- | libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp | 116 | ||||
| -rw-r--r-- | libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h | 21 | ||||
| -rw-r--r-- | libs/ultrahdr/jpegencoderhelper.cpp | 73 | ||||
| -rw-r--r-- | libs/ultrahdr/jpegr.cpp | 109 | ||||
| -rw-r--r-- | libs/ultrahdr/tests/gainmapmath_test.cpp | 17 | ||||
| -rw-r--r-- | libs/ultrahdr/tests/jpegencoderhelper_test.cpp | 25 | ||||
| -rw-r--r-- | libs/ultrahdr/tests/jpegr_test.cpp | 118 |
7 files changed, 298 insertions, 181 deletions
diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp index 5d6242cb56..bf9b0318bd 100644 --- a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp +++ b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp @@ -23,8 +23,8 @@ // User include files #include "ultrahdr/gainmapmath.h" -#include "ultrahdr/jpegencoderhelper.h" #include "ultrahdr/jpegdecoderhelper.h" +#include "ultrahdr/jpegencoderhelper.h" #include "utils/Log.h" using namespace android::ultrahdr; @@ -50,7 +50,7 @@ public: UltraHdrEncFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; void process(); void fillP010Buffer(uint16_t* data, int width, int height, int stride); - void fill420Buffer(uint8_t* data, int size); + void fill420Buffer(uint8_t* data, int width, int height, int stride); private: FuzzedDataProvider mFdp; @@ -73,13 +73,18 @@ void UltraHdrEncFuzzer::fillP010Buffer(uint16_t* data, int width, int height, in } } -void UltraHdrEncFuzzer::fill420Buffer(uint8_t* data, int size) { +void UltraHdrEncFuzzer::fill420Buffer(uint8_t* data, int width, int height, int stride) { + uint8_t* tmp = data; std::vector<uint8_t> buffer(16); mFdp.ConsumeData(buffer.data(), buffer.size()); - for (int i = 0; i < size; i += buffer.size()) { - memcpy(data + i, buffer.data(), std::min((int)buffer.size(), (size - i))); - std::shuffle(buffer.begin(), buffer.end(), - std::default_random_engine(std::random_device{}())); + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i += buffer.size()) { + memcpy(tmp + i, buffer.data(), + std::min((int)buffer.size(), (width - i)) * sizeof(*data)); + std::shuffle(buffer.begin(), buffer.end(), + std::default_random_engine(std::random_device{}())); + } + tmp += stride; } } @@ -120,9 +125,10 @@ void UltraHdrEncFuzzer::process() { int height = mFdp.ConsumeIntegralInRange<int>(kMinHeight, kMaxHeight); height = (height >> 1) << 1; - std::unique_ptr<uint16_t[]> bufferY = nullptr; - std::unique_ptr<uint16_t[]> bufferUV = nullptr; - std::unique_ptr<uint8_t[]> yuv420ImgRaw = nullptr; + std::unique_ptr<uint16_t[]> bufferYHdr = nullptr; + std::unique_ptr<uint16_t[]> bufferUVHdr = nullptr; + std::unique_ptr<uint8_t[]> bufferYSdr = nullptr; + std::unique_ptr<uint8_t[]> bufferUVSdr = nullptr; std::unique_ptr<uint8_t[]> grayImgRaw = nullptr; if (muxSwitch != 4) { // init p010 image @@ -136,30 +142,29 @@ void UltraHdrEncFuzzer::process() { int bppP010 = 2; if (isUVContiguous) { size_t p010Size = yStride * height * 3 / 2; - bufferY = std::make_unique<uint16_t[]>(p010Size); - p010Img.data = bufferY.get(); + bufferYHdr = std::make_unique<uint16_t[]>(p010Size); + p010Img.data = bufferYHdr.get(); p010Img.chroma_data = nullptr; p010Img.chroma_stride = 0; - fillP010Buffer(bufferY.get(), width, height, yStride); - fillP010Buffer(bufferY.get() + yStride * height, width, height / 2, yStride); + fillP010Buffer(bufferYHdr.get(), width, height, yStride); + fillP010Buffer(bufferYHdr.get() + yStride * height, width, height / 2, yStride); } else { int uvStride = mFdp.ConsumeIntegralInRange<int>(width, width + 128); size_t p010YSize = yStride * height; - bufferY = std::make_unique<uint16_t[]>(p010YSize); - p010Img.data = bufferY.get(); - fillP010Buffer(bufferY.get(), width, height, yStride); + bufferYHdr = std::make_unique<uint16_t[]>(p010YSize); + p010Img.data = bufferYHdr.get(); + fillP010Buffer(bufferYHdr.get(), width, height, yStride); size_t p010UVSize = uvStride * p010Img.height / 2; - bufferUV = std::make_unique<uint16_t[]>(p010UVSize); - p010Img.chroma_data = bufferUV.get(); + bufferUVHdr = std::make_unique<uint16_t[]>(p010UVSize); + p010Img.chroma_data = bufferUVHdr.get(); p010Img.chroma_stride = uvStride; - fillP010Buffer(bufferUV.get(), width, height / 2, uvStride); + fillP010Buffer(bufferUVHdr.get(), width, height / 2, uvStride); } } else { - int map_width = width / kMapDimensionScaleFactor; - int map_height = height / kMapDimensionScaleFactor; - map_width = static_cast<size_t>(floor((map_width + kJpegBlock - 1) / kJpegBlock)) * - kJpegBlock; - map_height = ((map_height + 1) >> 1) << 1; + size_t map_width = static_cast<size_t>( + floor((width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); + size_t map_height = static_cast<size_t>( + floor((height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); // init 400 image grayImg.width = map_width; grayImg.height = map_height; @@ -168,7 +173,7 @@ void UltraHdrEncFuzzer::process() { const size_t graySize = map_width * map_height; grayImgRaw = std::make_unique<uint8_t[]>(graySize); grayImg.data = grayImgRaw.get(); - fill420Buffer(grayImgRaw.get(), graySize); + fill420Buffer(grayImgRaw.get(), map_width, map_height, map_width); grayImg.chroma_data = nullptr; grayImg.luma_stride = 0; grayImg.chroma_stride = 0; @@ -176,17 +181,38 @@ void UltraHdrEncFuzzer::process() { if (muxSwitch > 0) { // init 420 image + bool isUVContiguous = mFdp.ConsumeBool(); + bool hasYStride = mFdp.ConsumeBool(); + int yStride = hasYStride ? mFdp.ConsumeIntegralInRange<int>(width, width + 128) : width; yuv420Img.width = width; yuv420Img.height = height; yuv420Img.colorGamut = yuv420Cg; - - const size_t yuv420Size = (yuv420Img.width * yuv420Img.height * 3) / 2; - yuv420ImgRaw = std::make_unique<uint8_t[]>(yuv420Size); - yuv420Img.data = yuv420ImgRaw.get(); - fill420Buffer(yuv420ImgRaw.get(), yuv420Size); - yuv420Img.chroma_data = nullptr; - yuv420Img.luma_stride = 0; - yuv420Img.chroma_stride = 0; + yuv420Img.luma_stride = hasYStride ? yStride : 0; + if (isUVContiguous) { + size_t yuv420Size = yStride * height * 3 / 2; + bufferYSdr = std::make_unique<uint8_t[]>(yuv420Size); + yuv420Img.data = bufferYSdr.get(); + yuv420Img.chroma_data = nullptr; + yuv420Img.chroma_stride = 0; + fill420Buffer(bufferYSdr.get(), width, height, yStride); + fill420Buffer(bufferYSdr.get() + yStride * height, width / 2, height / 2, + yStride / 2); + fill420Buffer(bufferYSdr.get() + yStride * height * 5 / 4, width / 2, height / 2, + yStride / 2); + } else { + int uvStride = mFdp.ConsumeIntegralInRange<int>(width / 2, width / 2 + 128); + size_t yuv420YSize = yStride * height; + bufferYSdr = std::make_unique<uint8_t[]>(yuv420YSize); + yuv420Img.data = bufferYSdr.get(); + fill420Buffer(bufferYSdr.get(), width, height, yStride); + size_t yuv420UVSize = uvStride * yuv420Img.height / 2 * 2; + bufferUVSdr = std::make_unique<uint8_t[]>(yuv420UVSize); + yuv420Img.chroma_data = bufferYSdr.get(); + yuv420Img.chroma_stride = uvStride; + fill420Buffer(bufferUVSdr.get(), width / 2, height / 2, uvStride); + fill420Buffer(bufferUVSdr.get() + uvStride * height / 2, width / 2, height / 2, + uvStride); + } } // dest @@ -203,6 +229,8 @@ void UltraHdrEncFuzzer::process() { std::cout << "p010 luma stride " << p010Img.luma_stride << std::endl; std::cout << "p010 chroma stride " << p010Img.chroma_stride << std::endl; std::cout << "420 color gamut " << yuv420Img.colorGamut << std::endl; + std::cout << "420 luma stride " << yuv420Img.luma_stride << std::endl; + std::cout << "420 chroma stride " << yuv420Img.chroma_stride << std::endl; std::cout << "quality factor " << quality << std::endl; #endif @@ -217,8 +245,19 @@ void UltraHdrEncFuzzer::process() { } else { // compressed img JpegEncoderHelper encoder; - if (encoder.compressImage(yuv420Img.data, yuv420Img.width, yuv420Img.height, quality, - nullptr, 0)) { + struct jpegr_uncompressed_struct yuv420ImgCopy = yuv420Img; + if (yuv420ImgCopy.luma_stride == 0) yuv420ImgCopy.luma_stride = yuv420Img.width; + if (!yuv420ImgCopy.chroma_data) { + uint8_t* data = reinterpret_cast<uint8_t*>(yuv420Img.data); + yuv420ImgCopy.chroma_data = data + yuv420Img.luma_stride * yuv420Img.height; + yuv420ImgCopy.chroma_stride = yuv420Img.luma_stride >> 1; + } + + if (encoder.compressImage(reinterpret_cast<uint8_t*>(yuv420ImgCopy.data), + reinterpret_cast<uint8_t*>(yuv420ImgCopy.chroma_data), + yuv420ImgCopy.width, yuv420ImgCopy.height, + yuv420ImgCopy.luma_stride, yuv420ImgCopy.chroma_stride, + quality, nullptr, 0)) { jpegImg.length = encoder.getCompressedImageSize(); jpegImg.maxLength = jpegImg.length; jpegImg.data = encoder.getCompressedImagePtr(); @@ -233,8 +272,9 @@ void UltraHdrEncFuzzer::process() { } else if (muxSwitch == 4) { // api 4 jpegImgR.length = 0; JpegEncoderHelper gainMapEncoder; - if (gainMapEncoder.compressImage(grayImg.data, grayImg.width, grayImg.height, - quality, nullptr, 0, true)) { + if (gainMapEncoder.compressImage(reinterpret_cast<uint8_t*>(grayImg.data), + nullptr, grayImg.width, grayImg.height, + grayImg.width, 0, quality, nullptr, 0)) { jpegGainMap.length = gainMapEncoder.getCompressedImageSize(); jpegGainMap.maxLength = jpegImg.length; jpegGainMap.data = gainMapEncoder.getCompressedImagePtr(); diff --git a/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h b/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h index 2c6778e299..9d06415cb3 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h +++ b/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h @@ -19,6 +19,7 @@ // We must include cstdio before jpeglib.h. It is a requirement of libjpeg. #include <cstdio> +#include <vector> extern "C" { #include <jerror.h> @@ -26,10 +27,11 @@ extern "C" { } #include <utils/Errors.h> -#include <vector> namespace android::ultrahdr { +#define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m)) + /* * Encapsulates a converter from raw image (YUV420planer or grey-scale) to JPEG format. * This class is not thread-safe. @@ -46,8 +48,9 @@ public: * ICC segment which will be added to the compressed image. * Returns false if errors occur during compression. */ - bool compressImage(const void* image, int width, int height, int quality, - const void* iccBuffer, unsigned int iccSize, bool isSingleChannel = false); + bool compressImage(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, int height, + int lumaStride, int chromaStride, int quality, const void* iccBuffer, + unsigned int iccSize); /* * Returns the compressed JPEG buffer pointer. This method must be called only after calling @@ -66,6 +69,7 @@ public: * We must pass at least 16 scanlines according to libjpeg documentation. */ static const int kCompressBatchSize = 16; + private: // initDestination(), emptyOutputBuffer() and emptyOutputBuffer() are callback functions to be // passed into jpeg library. @@ -75,15 +79,16 @@ private: static void outputErrorMessage(j_common_ptr cinfo); // Returns false if errors occur. - bool encode(const void* inYuv, int width, int height, int jpegQuality, - const void* iccBuffer, unsigned int iccSize, bool isSingleChannel); + bool encode(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, int height, + int lumaStride, int chromaStride, int quality, const void* iccBuffer, + unsigned int iccSize); void setJpegDestination(jpeg_compress_struct* cinfo); void setJpegCompressStruct(int width, int height, int quality, jpeg_compress_struct* cinfo, bool isSingleChannel); // Returns false if errors occur. - bool compress(jpeg_compress_struct* cinfo, const uint8_t* image, bool isSingleChannel); - bool compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yuv); - bool compressSingleChannel(jpeg_compress_struct* cinfo, const uint8_t* image); + bool compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, const uint8_t* uvBuffer, + int lumaStride, int chromaStride); + bool compressY(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, int lumaStride); // The block size for encoded jpeg image buffer. static const int kBlockSize = 16384; diff --git a/libs/ultrahdr/jpegencoderhelper.cpp b/libs/ultrahdr/jpegencoderhelper.cpp index 9394a83e46..13ae7424d5 100644 --- a/libs/ultrahdr/jpegencoderhelper.cpp +++ b/libs/ultrahdr/jpegencoderhelper.cpp @@ -23,8 +23,6 @@ namespace android::ultrahdr { -#define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m)) - // The destination manager that can access |mResultBuffer| in JpegEncoderHelper. struct destination_mgr { struct jpeg_destination_mgr mgr; @@ -35,11 +33,12 @@ JpegEncoderHelper::JpegEncoderHelper() {} JpegEncoderHelper::~JpegEncoderHelper() {} -bool JpegEncoderHelper::compressImage(const void* image, int width, int height, int quality, - const void* iccBuffer, unsigned int iccSize, - bool isSingleChannel) { +bool JpegEncoderHelper::compressImage(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, + int height, int lumaStride, int chromaStride, int quality, + const void* iccBuffer, unsigned int iccSize) { mResultBuffer.clear(); - if (!encode(image, width, height, quality, iccBuffer, iccSize, isSingleChannel)) { + if (!encode(yBuffer, uvBuffer, width, height, lumaStride, chromaStride, quality, iccBuffer, + iccSize)) { return false; } ALOGI("Compressed JPEG: %d[%dx%d] -> %zu bytes", (width * height * 12) / 8, width, height, @@ -87,25 +86,24 @@ void JpegEncoderHelper::outputErrorMessage(j_common_ptr cinfo) { ALOGE("%s\n", buffer); } -bool JpegEncoderHelper::encode(const void* image, int width, int height, int jpegQuality, - const void* iccBuffer, unsigned int iccSize, bool isSingleChannel) { +bool JpegEncoderHelper::encode(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, + int height, int lumaStride, int chromaStride, int quality, + const void* iccBuffer, unsigned int iccSize) { jpeg_compress_struct cinfo; jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); - // Override output_message() to print error log with ALOGE(). cinfo.err->output_message = &outputErrorMessage; jpeg_create_compress(&cinfo); setJpegDestination(&cinfo); - - setJpegCompressStruct(width, height, jpegQuality, &cinfo, isSingleChannel); + setJpegCompressStruct(width, height, quality, &cinfo, uvBuffer == nullptr); jpeg_start_compress(&cinfo, TRUE); - if (iccBuffer != nullptr && iccSize > 0) { jpeg_write_marker(&cinfo, JPEG_APP0 + 2, static_cast<const JOCTET*>(iccBuffer), iccSize); } - - bool status = compress(&cinfo, static_cast<const uint8_t*>(image), isSingleChannel); + bool status = cinfo.num_components == 1 + ? compressY(&cinfo, yBuffer, lumaStride) + : compressYuv(&cinfo, yBuffer, uvBuffer, lumaStride, chromaStride); jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); @@ -141,27 +139,23 @@ void JpegEncoderHelper::setJpegCompressStruct(int width, int height, int quality } } -bool JpegEncoderHelper::compress(jpeg_compress_struct* cinfo, const uint8_t* image, - bool isSingleChannel) { - return isSingleChannel ? compressSingleChannel(cinfo, image) : compressYuv(cinfo, image); -} - -bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yuv) { +bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, + const uint8_t* uvBuffer, int lumaStride, int chromaStride) { JSAMPROW y[kCompressBatchSize]; JSAMPROW cb[kCompressBatchSize / 2]; JSAMPROW cr[kCompressBatchSize / 2]; JSAMPARRAY planes[3]{y, cb, cr}; - size_t y_plane_size = cinfo->image_width * cinfo->image_height; - size_t uv_plane_size = y_plane_size / 4; - uint8_t* y_plane = const_cast<uint8_t*>(yuv); - uint8_t* u_plane = const_cast<uint8_t*>(yuv + y_plane_size); - uint8_t* v_plane = const_cast<uint8_t*>(yuv + y_plane_size + uv_plane_size); + size_t y_plane_size = lumaStride * cinfo->image_height; + size_t u_plane_size = chromaStride * cinfo->image_height / 2; + uint8_t* y_plane = const_cast<uint8_t*>(yBuffer); + uint8_t* u_plane = const_cast<uint8_t*>(uvBuffer); + uint8_t* v_plane = const_cast<uint8_t*>(u_plane + u_plane_size); std::unique_ptr<uint8_t[]> empty = std::make_unique<uint8_t[]>(cinfo->image_width); memset(empty.get(), 0, cinfo->image_width); const int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize); - const bool is_width_aligned = (aligned_width == cinfo->image_width); + const bool need_padding = (lumaStride < aligned_width); std::unique_ptr<uint8_t[]> buffer_intrm = nullptr; uint8_t* y_plane_intrm = nullptr; uint8_t* u_plane_intrm = nullptr; @@ -170,7 +164,7 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* JSAMPROW cb_intrm[kCompressBatchSize / 2]; JSAMPROW cr_intrm[kCompressBatchSize / 2]; JSAMPARRAY planes_intrm[3]{y_intrm, cb_intrm, cr_intrm}; - if (!is_width_aligned) { + if (need_padding) { size_t mcu_row_size = aligned_width * kCompressBatchSize * 3 / 2; buffer_intrm = std::make_unique<uint8_t[]>(mcu_row_size); y_plane_intrm = buffer_intrm.get(); @@ -195,11 +189,11 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* for (int i = 0; i < kCompressBatchSize; ++i) { size_t scanline = cinfo->next_scanline + i; if (scanline < cinfo->image_height) { - y[i] = y_plane + scanline * cinfo->image_width; + y[i] = y_plane + scanline * lumaStride; } else { y[i] = empty.get(); } - if (!is_width_aligned) { + if (need_padding) { memcpy(y_intrm[i], y[i], cinfo->image_width); } } @@ -207,18 +201,18 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* for (int i = 0; i < kCompressBatchSize / 2; ++i) { size_t scanline = cinfo->next_scanline / 2 + i; if (scanline < cinfo->image_height / 2) { - int offset = scanline * (cinfo->image_width / 2); + int offset = scanline * chromaStride; cb[i] = u_plane + offset; cr[i] = v_plane + offset; } else { cb[i] = cr[i] = empty.get(); } - if (!is_width_aligned) { + if (need_padding) { memcpy(cb_intrm[i], cb[i], cinfo->image_width / 2); memcpy(cr_intrm[i], cr[i], cinfo->image_width / 2); } } - int processed = jpeg_write_raw_data(cinfo, is_width_aligned ? planes : planes_intrm, + int processed = jpeg_write_raw_data(cinfo, need_padding ? planes_intrm : planes, kCompressBatchSize); if (processed != kCompressBatchSize) { ALOGE("Number of processed lines does not equal input lines."); @@ -228,22 +222,23 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* return true; } -bool JpegEncoderHelper::compressSingleChannel(jpeg_compress_struct* cinfo, const uint8_t* image) { +bool JpegEncoderHelper::compressY(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, + int lumaStride) { JSAMPROW y[kCompressBatchSize]; JSAMPARRAY planes[1]{y}; - uint8_t* y_plane = const_cast<uint8_t*>(image); + uint8_t* y_plane = const_cast<uint8_t*>(yBuffer); std::unique_ptr<uint8_t[]> empty = std::make_unique<uint8_t[]>(cinfo->image_width); memset(empty.get(), 0, cinfo->image_width); const int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize); - bool is_width_aligned = (aligned_width == cinfo->image_width); + const bool need_padding = (lumaStride < aligned_width); std::unique_ptr<uint8_t[]> buffer_intrm = nullptr; uint8_t* y_plane_intrm = nullptr; uint8_t* u_plane_intrm = nullptr; JSAMPROW y_intrm[kCompressBatchSize]; JSAMPARRAY planes_intrm[]{y_intrm}; - if (!is_width_aligned) { + if (need_padding) { size_t mcu_row_size = aligned_width * kCompressBatchSize; buffer_intrm = std::make_unique<uint8_t[]>(mcu_row_size); y_plane_intrm = buffer_intrm.get(); @@ -257,15 +252,15 @@ bool JpegEncoderHelper::compressSingleChannel(jpeg_compress_struct* cinfo, const for (int i = 0; i < kCompressBatchSize; ++i) { size_t scanline = cinfo->next_scanline + i; if (scanline < cinfo->image_height) { - y[i] = y_plane + scanline * cinfo->image_width; + y[i] = y_plane + scanline * lumaStride; } else { y[i] = empty.get(); } - if (!is_width_aligned) { + if (need_padding) { memcpy(y_intrm[i], y[i], cinfo->image_width); } } - int processed = jpeg_write_raw_data(cinfo, is_width_aligned ? planes : planes_intrm, + int processed = jpeg_write_raw_data(cinfo, need_padding ? planes_intrm : planes, kCompressBatchSize); if (processed != kCompressBatchSize / 2) { ALOGE("Number of processed lines does not equal input lines."); diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp index fdfbb9cec2..dc439d785a 100644 --- a/libs/ultrahdr/jpegr.cpp +++ b/libs/ultrahdr/jpegr.cpp @@ -185,21 +185,18 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfe p010_image.chroma_stride = p010_image.luma_stride; } + const int yu420_luma_stride = ALIGNM(p010_image.width, kJpegBlock); unique_ptr<uint8_t[]> yuv420_image_data = - make_unique<uint8_t[]>(p010_image.width * p010_image.height * 3 / 2); + make_unique<uint8_t[]>(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, - .luma_stride = 0, + .luma_stride = yu420_luma_stride, .chroma_data = nullptr, - .chroma_stride = 0}; - if (yuv420_image.luma_stride == 0) yuv420_image.luma_stride = yuv420_image.width; - if (!yuv420_image.chroma_data) { - uint8_t* data = reinterpret_cast<uint8_t*>(yuv420_image.data); - yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height; - yuv420_image.chroma_stride = yuv420_image.luma_stride >> 1; - } + .chroma_stride = yu420_luma_stride >> 1}; + uint8_t* data = reinterpret_cast<uint8_t*>(yuv420_image.data); + yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height; // tone map JPEGR_CHECK(toneMap(&p010_image, &yuv420_image)); @@ -230,7 +227,10 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfe // compress 420 image JpegEncoderHelper jpeg_enc_obj_yuv420; - if (!jpeg_enc_obj_yuv420.compressImage(yuv420_image.data, yuv420_image.width, yuv420_image.height, + if (!jpeg_enc_obj_yuv420.compressImage(reinterpret_cast<uint8_t*>(yuv420_image.data), + reinterpret_cast<uint8_t*>(yuv420_image.chroma_data), + yuv420_image.width, yuv420_image.height, + yuv420_image.luma_stride, yuv420_image.chroma_stride, quality, icc->getData(), icc->getLength())) { return ERROR_JPEGR_ENCODE_ERROR; } @@ -305,13 +305,15 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, unique_ptr<uint8_t[]> yuv_420_bt601_data; // Convert to bt601 YUV encoding for JPEG encode if (yuv420_image.colorGamut != ULTRAHDR_COLORGAMUT_P3) { - yuv_420_bt601_data = make_unique<uint8_t[]>(yuv420_image.width * yuv420_image.height * 3 / 2); + const int yuv_420_bt601_luma_stride = ALIGNM(yuv420_image.width, kJpegBlock); + yuv_420_bt601_data = + make_unique<uint8_t[]>(yuv_420_bt601_luma_stride * yuv420_image.height * 3 / 2); yuv420_bt601_image.data = yuv_420_bt601_data.get(); yuv420_bt601_image.colorGamut = yuv420_image.colorGamut; - yuv420_bt601_image.luma_stride = yuv420_image.width; + yuv420_bt601_image.luma_stride = yuv_420_bt601_luma_stride; uint8_t* data = reinterpret_cast<uint8_t*>(yuv420_bt601_image.data); - yuv420_bt601_image.chroma_data = data + yuv420_bt601_image.luma_stride * yuv420_image.height; - yuv420_bt601_image.chroma_stride = yuv420_bt601_image.luma_stride >> 1; + yuv420_bt601_image.chroma_data = data + yuv_420_bt601_luma_stride * yuv420_image.height; + yuv420_bt601_image.chroma_stride = yuv_420_bt601_luma_stride >> 1; { // copy luma @@ -322,6 +324,10 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, } else { for (size_t i = 0; i < yuv420_image.height; i++) { memcpy(y_dst, y_src, yuv420_image.width); + if (yuv420_image.width != yuv420_bt601_image.luma_stride) { + memset(y_dst + yuv420_image.width, 0, + yuv420_bt601_image.luma_stride - yuv420_image.width); + } y_dst += yuv420_bt601_image.luma_stride; y_src += yuv420_image.luma_stride; } @@ -342,6 +348,12 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, for (size_t i = 0; i < yuv420_image.height / 2; i++) { memcpy(cb_dst, cb_src, yuv420_image.width / 2); memcpy(cr_dst, cr_src, yuv420_image.width / 2); + if (yuv420_bt601_image.width / 2 != yuv420_bt601_image.chroma_stride) { + memset(cb_dst + yuv420_image.width / 2, 0, + yuv420_bt601_image.chroma_stride - yuv420_image.width / 2); + memset(cr_dst + yuv420_image.width / 2, 0, + yuv420_bt601_image.chroma_stride - yuv420_image.width / 2); + } cb_dst += yuv420_bt601_image.chroma_stride; cb_src += yuv420_image.chroma_stride; cr_dst += yuv420_bt601_image.chroma_stride; @@ -353,8 +365,11 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, // compress 420 image JpegEncoderHelper jpeg_enc_obj_yuv420; - if (!jpeg_enc_obj_yuv420.compressImage(yuv420_bt601_image.data, yuv420_bt601_image.width, - yuv420_bt601_image.height, quality, icc->getData(), + if (!jpeg_enc_obj_yuv420.compressImage(reinterpret_cast<uint8_t*>(yuv420_bt601_image.data), + reinterpret_cast<uint8_t*>(yuv420_bt601_image.chroma_data), + yuv420_bt601_image.width, yuv420_bt601_image.height, + yuv420_bt601_image.luma_stride, + yuv420_bt601_image.chroma_stride, quality, icc->getData(), icc->getLength())) { return ERROR_JPEGR_ENCODE_ERROR; } @@ -697,9 +712,10 @@ status_t JpegR::compressGainMap(jr_uncompressed_ptr gainmap_image_ptr, } // Don't need to convert YUV to Bt601 since single channel - if (!jpeg_enc_obj_ptr->compressImage(gainmap_image_ptr->data, gainmap_image_ptr->width, - gainmap_image_ptr->height, kMapCompressQuality, nullptr, 0, - true /* isSingleChannel */)) { + if (!jpeg_enc_obj_ptr->compressImage(reinterpret_cast<uint8_t*>(gainmap_image_ptr->data), nullptr, + gainmap_image_ptr->width, gainmap_image_ptr->height, + gainmap_image_ptr->luma_stride, 0, kMapCompressQuality, + nullptr, 0)) { return ERROR_JPEGR_ENCODE_ERROR; } @@ -769,7 +785,9 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_transfer_function hdr_tf, ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr dest, bool sdr_is_601) { if (yuv420_image_ptr == nullptr || p010_image_ptr == nullptr || metadata == nullptr || - dest == nullptr) { + dest == nullptr || yuv420_image_ptr->data == nullptr || + yuv420_image_ptr->chroma_data == nullptr || p010_image_ptr->data == nullptr || + p010_image_ptr->chroma_data == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } if (yuv420_image_ptr->width != p010_image_ptr->width || @@ -940,7 +958,8 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_output_format output_format, float max_display_boost, jr_uncompressed_ptr dest) { if (yuv420_image_ptr == nullptr || gainmap_image_ptr == nullptr || metadata == nullptr || - dest == nullptr) { + dest == nullptr || yuv420_image_ptr->data == nullptr || + yuv420_image_ptr->chroma_data == nullptr || gainmap_image_ptr->data == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } if (metadata->version.compare(kJpegrVersion)) { @@ -970,7 +989,9 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, size_t map_height = static_cast<size_t>( floor((image_height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); if (map_width != gainmap_image_ptr->width || map_height != gainmap_image_ptr->height) { - ALOGE("gain map dimensions and primary image dimensions are not to scale"); + ALOGE("gain map dimensions and primary image dimensions are not to scale, computed gain map " + "resolution is %dx%d, received gain map resolution is %dx%d", + (int)map_width, (int)map_height, gainmap_image_ptr->width, gainmap_image_ptr->height); return ERROR_JPEGR_INVALID_INPUT_TYPE; } @@ -1314,27 +1335,35 @@ status_t JpegR::toneMap(jr_uncompressed_ptr src, jr_uncompressed_ptr dest) { return ERROR_JPEGR_INVALID_INPUT_TYPE; } uint16_t* src_y_data = reinterpret_cast<uint16_t*>(src->data); - uint16_t* src_uv_data = reinterpret_cast<uint16_t*>(src->chroma_data); uint8_t* dst_y_data = reinterpret_cast<uint8_t*>(dest->data); - uint8_t* dst_u_data = reinterpret_cast<uint8_t*>(dest->chroma_data); - size_t v_offset = (dest->chroma_stride * dest->height / 2); - uint8_t* dst_v_data = dst_u_data + v_offset; for (size_t y = 0; y < src->height; ++y) { + uint16_t* src_y_row = src_y_data + y * src->luma_stride; + uint8_t* dst_y_row = dst_y_data + y * dest->luma_stride; for (size_t x = 0; x < src->width; ++x) { - size_t src_y_idx = y * src->luma_stride + x; - size_t src_u_idx = (y >> 1) * src->chroma_stride + (x & ~0x1); - size_t src_v_idx = src_u_idx + 1; - - uint16_t y_uint = src_y_data[src_y_idx] >> 6; - uint16_t u_uint = src_uv_data[src_u_idx] >> 6; - uint16_t v_uint = src_uv_data[src_v_idx] >> 6; - - size_t dest_y_idx = x + y * dest->luma_stride; - size_t dest_chroma_idx = (x / 2) + (y / 2) * (dest->chroma_stride); - - dst_y_data[dest_y_idx] = static_cast<uint8_t>((y_uint >> 2) & 0xff); - dst_u_data[dest_chroma_idx] = static_cast<uint8_t>((u_uint >> 2) & 0xff); - dst_v_data[dest_chroma_idx] = static_cast<uint8_t>((v_uint >> 2) & 0xff); + uint16_t y_uint = src_y_row[x] >> 6; + dst_y_row[x] = static_cast<uint8_t>((y_uint >> 2) & 0xff); + } + if (dest->width != dest->luma_stride) { + memset(dst_y_row + dest->width, 0, dest->luma_stride - dest->width); + } + } + uint16_t* src_uv_data = reinterpret_cast<uint16_t*>(src->chroma_data); + uint8_t* dst_u_data = reinterpret_cast<uint8_t*>(dest->chroma_data); + size_t dst_v_offset = (dest->chroma_stride * dest->height / 2); + uint8_t* dst_v_data = dst_u_data + dst_v_offset; + for (size_t y = 0; y < src->height / 2; ++y) { + uint16_t* src_uv_row = src_uv_data + y * src->chroma_stride; + uint8_t* dst_u_row = dst_u_data + y * dest->chroma_stride; + uint8_t* dst_v_row = dst_v_data + y * dest->chroma_stride; + for (size_t x = 0; x < src->width / 2; ++x) { + uint16_t u_uint = src_uv_row[x << 1] >> 6; + uint16_t v_uint = src_uv_row[(x << 1) + 1] >> 6; + dst_u_row[x] = static_cast<uint8_t>((u_uint >> 2) & 0xff); + dst_v_row[x] = static_cast<uint8_t>((v_uint >> 2) & 0xff); + } + if (dest->width / 2 != dest->chroma_stride) { + memset(dst_u_row + dest->width / 2, 0, dest->chroma_stride - dest->width / 2); + memset(dst_v_row + dest->width / 2, 0, dest->chroma_stride - dest->width / 2); } } dest->colorGamut = src->colorGamut; diff --git a/libs/ultrahdr/tests/gainmapmath_test.cpp b/libs/ultrahdr/tests/gainmapmath_test.cpp index 69cd36cd46..7c2d076992 100644 --- a/libs/ultrahdr/tests/gainmapmath_test.cpp +++ b/libs/ultrahdr/tests/gainmapmath_test.cpp @@ -120,7 +120,7 @@ public: 0xB0, 0xB1, 0xB2, 0xB3, }; - return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709 }; + return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709, pixels + 16, 4, 2 }; } Color (*Yuv420Colors())[4] { @@ -153,7 +153,7 @@ public: 0xA0 << 6, 0xB0 << 6, 0xA1 << 6, 0xB1 << 6, 0xA2 << 6, 0xB2 << 6, 0xA3 << 6, 0xB3 << 6, }; - return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709 }; + return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709, pixels + 16, 4, 4 }; } Color (*P010Colors())[4] { @@ -625,7 +625,7 @@ TEST_F(GainMapMathTest, Bt2100ToBt601YuvConversion) { EXPECT_YUV_NEAR(yuv2100To601(yuv_b), P3YuvBlue()); } -TEST_F(GainMapMathTest, DISABLED_TransformYuv420) { +TEST_F(GainMapMathTest, TransformYuv420) { ColorTransformFn transforms[] = { yuv709To601, yuv709To2100, yuv601To709, yuv601To2100, yuv2100To709, yuv2100To601 }; for (const ColorTransformFn& transform : transforms) { @@ -636,6 +636,9 @@ TEST_F(GainMapMathTest, DISABLED_TransformYuv420) { memcpy(out_buf.get(), input.data, out_buf_size); jpegr_uncompressed_struct output = Yuv420Image(); output.data = out_buf.get(); + output.chroma_data = out_buf.get() + input.width * input.height; + output.luma_stride = input.width; + output.chroma_stride = input.width / 2; transformYuv420(&output, 1, 1, transform); @@ -1042,7 +1045,7 @@ TEST_F(GainMapMathTest, ApplyGain) { applyGain(e, 1.0f, &metadata, displayBoost)); } -TEST_F(GainMapMathTest, DISABLED_GetYuv420Pixel) { +TEST_F(GainMapMathTest, GetYuv420Pixel) { jpegr_uncompressed_struct image = Yuv420Image(); Color (*colors)[4] = Yuv420Colors(); @@ -1053,7 +1056,7 @@ TEST_F(GainMapMathTest, DISABLED_GetYuv420Pixel) { } } -TEST_F(GainMapMathTest, DISABLED_GetP010Pixel) { +TEST_F(GainMapMathTest, GetP010Pixel) { jpegr_uncompressed_struct image = P010Image(); Color (*colors)[4] = P010Colors(); @@ -1064,7 +1067,7 @@ TEST_F(GainMapMathTest, DISABLED_GetP010Pixel) { } } -TEST_F(GainMapMathTest, DISABLED_SampleYuv420) { +TEST_F(GainMapMathTest, SampleYuv420) { jpegr_uncompressed_struct image = Yuv420Image(); Color (*colors)[4] = Yuv420Colors(); @@ -1090,7 +1093,7 @@ TEST_F(GainMapMathTest, DISABLED_SampleYuv420) { } } -TEST_F(GainMapMathTest, DISABLED_SampleP010) { +TEST_F(GainMapMathTest, SampleP010) { jpegr_uncompressed_struct image = P010Image(); Color (*colors)[4] = P010Colors(); diff --git a/libs/ultrahdr/tests/jpegencoderhelper_test.cpp b/libs/ultrahdr/tests/jpegencoderhelper_test.cpp index f0e1fa4968..33cb9f658f 100644 --- a/libs/ultrahdr/tests/jpegencoderhelper_test.cpp +++ b/libs/ultrahdr/tests/jpegencoderhelper_test.cpp @@ -42,6 +42,7 @@ public: }; JpegEncoderHelperTest(); ~JpegEncoderHelperTest(); + protected: virtual void SetUp(); virtual void TearDown(); @@ -103,24 +104,32 @@ void JpegEncoderHelperTest::TearDown() {} TEST_F(JpegEncoderHelperTest, encodeAlignedImage) { JpegEncoderHelper encoder; - EXPECT_TRUE(encoder.compressImage(mAlignedImage.buffer.get(), mAlignedImage.width, - mAlignedImage.height, JPEG_QUALITY, NULL, 0)); + EXPECT_TRUE(encoder.compressImage(mAlignedImage.buffer.get(), + mAlignedImage.buffer.get() + + mAlignedImage.width * mAlignedImage.height, + mAlignedImage.width, mAlignedImage.height, + mAlignedImage.width, mAlignedImage.width / 2, JPEG_QUALITY, + NULL, 0)); ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0)); } TEST_F(JpegEncoderHelperTest, encodeUnalignedImage) { JpegEncoderHelper encoder; - EXPECT_TRUE(encoder.compressImage(mUnalignedImage.buffer.get(), mUnalignedImage.width, - mUnalignedImage.height, JPEG_QUALITY, NULL, 0)); + EXPECT_TRUE(encoder.compressImage(mUnalignedImage.buffer.get(), + mUnalignedImage.buffer.get() + + mUnalignedImage.width * mUnalignedImage.height, + mUnalignedImage.width, mUnalignedImage.height, + mUnalignedImage.width, mUnalignedImage.width / 2, + JPEG_QUALITY, NULL, 0)); ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0)); } TEST_F(JpegEncoderHelperTest, encodeSingleChannelImage) { JpegEncoderHelper encoder; - EXPECT_TRUE(encoder.compressImage(mSingleChannelImage.buffer.get(), mSingleChannelImage.width, - mSingleChannelImage.height, JPEG_QUALITY, NULL, 0, true)); + EXPECT_TRUE(encoder.compressImage(mSingleChannelImage.buffer.get(), nullptr, + mSingleChannelImage.width, mSingleChannelImage.height, + mSingleChannelImage.width, 0, JPEG_QUALITY, NULL, 0)); ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0)); } -} // namespace android::ultrahdr - +} // namespace android::ultrahdr diff --git a/libs/ultrahdr/tests/jpegr_test.cpp b/libs/ultrahdr/tests/jpegr_test.cpp index e69c50964a..a75086755a 100644 --- a/libs/ultrahdr/tests/jpegr_test.cpp +++ b/libs/ultrahdr/tests/jpegr_test.cpp @@ -1375,11 +1375,21 @@ TEST(JpegRTest, writeXmpThenRead) { EXPECT_FLOAT_EQ(metadata_expected.hdrCapacityMax, metadata_read.hdrCapacityMax); } +class JpegRAPIEncodeAndDecodeTest + : public ::testing::TestWithParam<std::tuple<ultrahdr_color_gamut, ultrahdr_color_gamut>> { +public: + JpegRAPIEncodeAndDecodeTest() + : mP010ColorGamut(std::get<0>(GetParam())), mYuv420ColorGamut(std::get<1>(GetParam())){}; + + const ultrahdr_color_gamut mP010ColorGamut; + const ultrahdr_color_gamut mYuv420ColorGamut; +}; + /* Test Encode API-0 and Decode */ -TEST(JpegRTest, EncodeAPI0AndDecodeTest) { +TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI0AndDecodeTest) { // reference encode UhdrUnCompressedStructWrapper rawImg(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg.allocateMemory()); ASSERT_TRUE(rawImg.loadRawResource(kYCbCrP010FileName)); UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); @@ -1392,8 +1402,8 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { // encode with luma stride set { UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); - ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut)); + ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 18, 0)); ASSERT_TRUE(rawImg2.allocateMemory()); ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); @@ -1410,8 +1420,8 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { // encode with luma and chroma stride set { UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); - ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 128, kImageWidth + 256)); + ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut)); + ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 18, kImageWidth + 28)); ASSERT_TRUE(rawImg2.setChromaMode(false)); ASSERT_TRUE(rawImg2.allocateMemory()); ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); @@ -1429,8 +1439,8 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { // encode with chroma stride set { UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); - ASSERT_TRUE(rawImg2.setImageStride(0, kImageWidth + 64)); + ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut)); + ASSERT_TRUE(rawImg2.setImageStride(0, kImageWidth + 34)); ASSERT_TRUE(rawImg2.setChromaMode(false)); ASSERT_TRUE(rawImg2.allocateMemory()); ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); @@ -1448,8 +1458,8 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { // encode with luma and chroma stride set but no chroma ptr { UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); - ASSERT_TRUE(rawImg2.setImageStride(kImageWidth, kImageWidth + 256)); + ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut)); + ASSERT_TRUE(rawImg2.setImageStride(kImageWidth, kImageWidth + 38)); ASSERT_TRUE(rawImg2.allocateMemory()); ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); @@ -1475,13 +1485,13 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { } /* Test Encode API-1 and Decode */ -TEST(JpegRTest, EncodeAPI1AndDecodeTest) { +TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI1AndDecodeTest) { UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImgP010.allocateMemory()); ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg420.allocateMemory()); ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName)); UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); @@ -1494,7 +1504,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma stride set p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1512,7 +1522,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma and chroma stride set p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1531,7 +1541,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with chroma stride set p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1550,7 +1560,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma and chroma stride set but no chroma ptr p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 64, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1568,8 +1578,8 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma stride set 420 { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); - ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 14, 0)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); @@ -1586,8 +1596,8 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma and chroma stride set 420 { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); - ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth / 2 + 256)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 46, kImageWidth / 2 + 34)); ASSERT_TRUE(rawImg2420.setChromaMode(false)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); @@ -1605,8 +1615,8 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with chroma stride set 420 { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); - ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth / 2 + 64)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); + ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth / 2 + 38)); ASSERT_TRUE(rawImg2420.setChromaMode(false)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); @@ -1624,8 +1634,8 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma and chroma stride set but no chroma ptr 420 { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); - ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth / 2 + 64)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 26, kImageWidth / 2 + 44)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); @@ -1652,13 +1662,13 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { } /* Test Encode API-2 and Decode */ -TEST(JpegRTest, EncodeAPI2AndDecodeTest) { +TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI2AndDecodeTest) { UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImgP010.allocateMemory()); ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg420.allocateMemory()); ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName)); UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); @@ -1675,7 +1685,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with luma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1693,7 +1703,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with luma and chroma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1712,7 +1722,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with chroma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1731,7 +1741,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with luma stride set { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, 0)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); @@ -1749,7 +1759,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with luma and chroma stride set { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth + 256)); ASSERT_TRUE(rawImg2420.setChromaMode(false)); ASSERT_TRUE(rawImg2420.allocateMemory()); @@ -1768,7 +1778,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with chroma stride set { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth + 64)); ASSERT_TRUE(rawImg2420.setChromaMode(false)); ASSERT_TRUE(rawImg2420.allocateMemory()); @@ -1797,9 +1807,9 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { } /* Test Encode API-3 and Decode */ -TEST(JpegRTest, EncodeAPI3AndDecodeTest) { +TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI3AndDecodeTest) { UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImgP010.allocateMemory()); ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); @@ -1816,7 +1826,7 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { // encode with luma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1834,7 +1844,7 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { // encode with luma and chroma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1853,7 +1863,7 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { // encode with chroma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1872,7 +1882,7 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { // encode with luma and chroma stride set and no chroma ptr { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 32, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1899,6 +1909,13 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api3_output.rgb")); } +INSTANTIATE_TEST_SUITE_P( + JpegRAPIParameterizedTests, JpegRAPIEncodeAndDecodeTest, + ::testing::Combine(::testing::Values(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, + ULTRAHDR_COLORGAMUT_BT2100), + ::testing::Values(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, + ULTRAHDR_COLORGAMUT_BT2100))); + // ============================================================================ // Profiling // ============================================================================ @@ -1966,7 +1983,7 @@ void JpegRBenchmark::BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, jr_u profileRecMap.elapsedTime() / (kProfileCount * 1000.f)); } -TEST(JpegRTest, DISABLED_ProfileGainMapFuncs) { +TEST(JpegRTest, ProfileGainMapFuncs) { UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); ASSERT_TRUE(rawImgP010.allocateMemory()); @@ -1980,6 +1997,25 @@ TEST(JpegRTest, DISABLED_ProfileGainMapFuncs) { .width = 0, .height = 0, .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + { + auto rawImg = rawImgP010.getImageHandle(); + if (rawImg->luma_stride == 0) rawImg->luma_stride = rawImg->width; + if (!rawImg->chroma_data) { + uint16_t* data = reinterpret_cast<uint16_t*>(rawImg->data); + rawImg->chroma_data = data + rawImg->luma_stride * rawImg->height; + rawImg->chroma_stride = rawImg->luma_stride; + } + } + { + auto rawImg = rawImg420.getImageHandle(); + if (rawImg->luma_stride == 0) rawImg->luma_stride = rawImg->width; + if (!rawImg->chroma_data) { + uint8_t* data = reinterpret_cast<uint8_t*>(rawImg->data); + rawImg->chroma_data = data + rawImg->luma_stride * rawImg->height; + rawImg->chroma_stride = rawImg->luma_stride / 2; + } + } + JpegRBenchmark benchmark; ASSERT_NO_FATAL_FAILURE(benchmark.BenchmarkGenerateGainMap(rawImg420.getImageHandle(), rawImgP010.getImageHandle(), &metadata, |