ultrahdr: update jpegencoderhelper to accept uncompressed struct fields
With this change we can now pass luma/chroma ptrs and stride information
to jpegencoderhelper class during compression. This by passes
intermediate copy whenever possible
Also updated fuzzer to incorporate 420 stride support
updated jpegr unit tests for more combinations of gamuts and unusual strides
Bug: 294218453
Test: ./ultrahdr_unit_test
Test: ./ultrahdr_enc_fuzzer
Change-Id: Ic50dd34b0c680618e73e0cb27f554b9bf8272e8f
diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp
index 5d6242c..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;
@@ -73,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;
}
}
@@ -120,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
@@ -136,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;
@@ -168,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;
@@ -176,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
@@ -203,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
@@ -217,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();
@@ -233,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();
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,