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,