JPEG/R: lift the checking criteria for width 8-alignment
JPEG/R library uses jpeg-turbo for JPEG encoding, which runs DCT transform on block size of 16x16 for luma, and 8x8 for chroma. The resolution in the bug report is not 16-aligned and it results in null pointer dereference for the last line in jpeg-turbo.
The original checking for 8-alignment width was wrong (should check
16-alignment). jpeg-turbo has some edge case handling for this case, and
it requires some extra room at the end of input. This change removed the checking criteria by adding a
padding zero method. A reason size of the padding zeros is a CB block,
which is 8x8, 64 bytes.
Bug: 277982036
Test: CTS: ImageReaderTest#testJpegR, uint test: jpegrencoderhelper_test.cpp
Change-Id: I1313a002db6d4bc63b32dc3dd3d6ccdf06779149
diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp
index 8e1dc8c..24d1911 100644
--- a/libs/ultrahdr/jpegr.cpp
+++ b/libs/ultrahdr/jpegr.cpp
@@ -66,9 +66,12 @@
// Map is quarter res / sixteenth size
static const size_t kMapDimensionScaleFactor = 4;
// JPEG block size.
-// JPEG encoding / decoding will require 8 x 8 DCT transform.
-// Width must be 8 dividable, and height must be 2 dividable.
-static const size_t kJpegBlock = 8;
+// JPEG encoding / decoding will require block based DCT transform 16 x 16 for luma,
+// and 8 x 8 for chroma.
+// Width must be 16 dividable for luma, and 8 dividable for chroma.
+// If this criteria is not ficilitated, we will pad zeros based on the required block size.
+static const size_t kJpegBlock = JpegEncoderHelper::kCompressBatchSize;
+static const size_t kJpegBlockSquare = kJpegBlock * kJpegBlock;
// JPEG compress quality (0 ~ 100) for gain map
static const int kMapCompressQuality = 85;
@@ -92,13 +95,6 @@
return ERROR_JPEGR_INVALID_NULL_PTR;
}
- if (uncompressed_p010_image->width % kJpegBlock != 0
- || uncompressed_p010_image->height % 2 != 0) {
- ALOGE("Image size can not be handled: %dx%d.",
- uncompressed_p010_image->width, uncompressed_p010_image->height);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
-
if (uncompressed_p010_image->luma_stride != 0
&& uncompressed_p010_image->luma_stride < uncompressed_p010_image->width) {
ALOGE("Image stride can not be smaller than width, stride=%d, width=%d",
@@ -157,8 +153,13 @@
metadata.version = kJpegrVersion;
jpegr_uncompressed_struct uncompressed_yuv_420_image;
- unique_ptr<uint8_t[]> uncompressed_yuv_420_image_data = make_unique<uint8_t[]>(
- uncompressed_p010_image->width * uncompressed_p010_image->height * 3 / 2);
+ size_t gain_map_length = uncompressed_p010_image->width * uncompressed_p010_image->height * 3 / 2;
+ // Pad a pseudo chroma block (kJpegBlock / 2) x (kJpegBlock / 2)
+ // if width is not kJpegBlock aligned.
+ if (uncompressed_p010_image->width % kJpegBlock != 0) {
+ gain_map_length += kJpegBlockSquare / 4;
+ }
+ unique_ptr<uint8_t[]> uncompressed_yuv_420_image_data = make_unique<uint8_t[]>(gain_map_length);
uncompressed_yuv_420_image.data = uncompressed_yuv_420_image_data.get();
JPEGR_CHECK(toneMap(uncompressed_p010_image, &uncompressed_yuv_420_image));