Merge changes Ic50dd34b,Ib8f5fbef,I058200ca into main
* changes:
ultrahdr: update jpegencoderhelper to accept uncompressed struct fields
ultrahdr: correct offset used during look ups
ultrahdr: minor fixes in encoder and decoder fuzzer
diff --git a/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp
index ad1d57a..f1f4035 100644
--- a/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp
+++ b/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp
@@ -54,7 +54,7 @@
std::cout << "input buffer size " << jpegImgR.length << std::endl;
std::cout << "image dimensions " << info.width << " x " << info.width << std::endl;
#endif
- size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_SDR) ? 4 : 8);
+ size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4);
jpegr_uncompressed_struct decodedJpegR;
auto decodedRaw = std::make_unique<uint8_t[]>(outSize);
decodedJpegR.data = decodedRaw.get();
diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp
index 1dce57c..bf9b031 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 @@
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;
@@ -60,11 +60,12 @@
uint16_t* tmp = data;
std::vector<uint16_t> buffer(16);
for (int i = 0; i < buffer.size(); i++) {
- buffer[i] = mFdp.ConsumeIntegralInRange<int>(0, (1 << 10) - 1);
+ buffer[i] = (mFdp.ConsumeIntegralInRange<int>(0, (1 << 10) - 1)) << 6;
}
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i += buffer.size()) {
- memcpy(data + i, buffer.data(), std::min((int)buffer.size(), (width - i)));
+ 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{}()));
}
@@ -72,13 +73,18 @@
}
}
-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;
}
}
@@ -119,9 +125,10 @@
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
@@ -135,30 +142,29 @@
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;
@@ -167,7 +173,7 @@
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;
@@ -175,17 +181,38 @@
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
@@ -202,6 +229,8 @@
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
@@ -216,8 +245,19 @@
} 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();
@@ -232,8 +272,9 @@
} 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();
@@ -264,7 +305,8 @@
jpegr_info_struct info{0, 0, &iccData, &exifData};
status = jpegHdr.getJPEGRInfo(&jpegImgR, &info);
if (status == android::OK) {
- size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_SDR) ? 4 : 8);
+ size_t outSize =
+ info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4);
jpegr_uncompressed_struct decodedJpegR;
auto decodedRaw = std::make_unique<uint8_t[]>(outSize);
decodedJpegR.data = decodedRaw.get();
diff --git a/libs/ultrahdr/gainmapmath.cpp b/libs/ultrahdr/gainmapmath.cpp
index e1c5085..ae9c4ca 100644
--- a/libs/ultrahdr/gainmapmath.cpp
+++ b/libs/ultrahdr/gainmapmath.cpp
@@ -168,7 +168,7 @@
// See IEC 61966-2-1, Equations F.5 and F.6.
float srgbInvOetfLUT(float e_gamma) {
- uint32_t value = static_cast<uint32_t>(e_gamma * kSrgbInvOETFNumEntries);
+ uint32_t value = static_cast<uint32_t>(e_gamma * (kSrgbInvOETFNumEntries - 1) + 0.5);
//TODO() : Remove once conversion modules have appropriate clamping in place
value = CLIP3(value, 0, kSrgbInvOETFNumEntries - 1);
return kSrgbInvOETF[value];
@@ -288,7 +288,7 @@
}
float hlgOetfLUT(float e) {
- uint32_t value = static_cast<uint32_t>(e * kHlgOETFNumEntries);
+ uint32_t value = static_cast<uint32_t>(e * (kHlgOETFNumEntries - 1) + 0.5);
//TODO() : Remove once conversion modules have appropriate clamping in place
value = CLIP3(value, 0, kHlgOETFNumEntries - 1);
@@ -315,7 +315,7 @@
}
float hlgInvOetfLUT(float e_gamma) {
- uint32_t value = static_cast<uint32_t>(e_gamma * kHlgInvOETFNumEntries);
+ uint32_t value = static_cast<uint32_t>(e_gamma * (kHlgInvOETFNumEntries - 1) + 0.5);
//TODO() : Remove once conversion modules have appropriate clamping in place
value = CLIP3(value, 0, kHlgInvOETFNumEntries - 1);
@@ -344,7 +344,7 @@
}
float pqOetfLUT(float e) {
- uint32_t value = static_cast<uint32_t>(e * kPqOETFNumEntries);
+ uint32_t value = static_cast<uint32_t>(e * (kPqOETFNumEntries - 1) + 0.5);
//TODO() : Remove once conversion modules have appropriate clamping in place
value = CLIP3(value, 0, kPqOETFNumEntries - 1);
@@ -376,7 +376,7 @@
}
float pqInvOetfLUT(float e_gamma) {
- uint32_t value = static_cast<uint32_t>(e_gamma * kPqInvOETFNumEntries);
+ uint32_t value = static_cast<uint32_t>(e_gamma * (kPqInvOETFNumEntries - 1) + 0.5);
//TODO() : Remove once conversion modules have appropriate clamping in place
value = CLIP3(value, 0, kPqInvOETFNumEntries - 1);
diff --git a/libs/ultrahdr/include/ultrahdr/gainmapmath.h b/libs/ultrahdr/include/ultrahdr/gainmapmath.h
index 50b4d2f..9f1238f 100644
--- a/libs/ultrahdr/include/ultrahdr/gainmapmath.h
+++ b/libs/ultrahdr/include/ultrahdr/gainmapmath.h
@@ -172,7 +172,7 @@
}
float getGainFactor(float gain) {
- uint32_t idx = static_cast<uint32_t>(gain * (kGainFactorNumEntries - 1));
+ uint32_t idx = static_cast<uint32_t>(gain * (kGainFactorNumEntries - 1) + 0.5);
//TODO() : Remove once conversion modules have appropriate clamping in place
idx = CLIP3(idx, 0, kGainFactorNumEntries - 1);
return mGainTable[idx];
diff --git a/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h b/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h
index 2c6778e..9d06415 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 @@
}
#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 @@
* 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 @@
* 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 @@
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 9394a83..13ae742 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() {}
-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 @@
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 @@
}
}
-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 @@
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 @@
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 @@
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 @@
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 @@
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 fdfbb9c..dc439d7 100644
--- a/libs/ultrahdr/jpegr.cpp
+++ b/libs/ultrahdr/jpegr.cpp
@@ -185,21 +185,18 @@
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 @@
// 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 @@
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 @@
} 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 @@
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 @@
// 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 @@
}
// 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 @@
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 @@
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 @@
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 @@
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 69cd36c..7c2d076 100644
--- a/libs/ultrahdr/tests/gainmapmath_test.cpp
+++ b/libs/ultrahdr/tests/gainmapmath_test.cpp
@@ -120,7 +120,7 @@
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 @@
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 @@
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 @@
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 @@
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_GetP010Pixel) {
+TEST_F(GainMapMathTest, GetP010Pixel) {
jpegr_uncompressed_struct image = P010Image();
Color (*colors)[4] = P010Colors();
@@ -1064,7 +1067,7 @@
}
}
-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_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 f0e1fa4..33cb9f6 100644
--- a/libs/ultrahdr/tests/jpegencoderhelper_test.cpp
+++ b/libs/ultrahdr/tests/jpegencoderhelper_test.cpp
@@ -42,6 +42,7 @@
};
JpegEncoderHelperTest();
~JpegEncoderHelperTest();
+
protected:
virtual void SetUp();
virtual void TearDown();
@@ -103,24 +104,32 @@
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 e69c509..a750867 100644
--- a/libs/ultrahdr/tests/jpegr_test.cpp
+++ b/libs/ultrahdr/tests/jpegr_test.cpp
@@ -1375,11 +1375,21 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
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 @@
.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,