libjpegrecoverymap: solve recovery map 8-pixel alignment
JPEG encoder requires width to be 8 aligned, and the recovery map is downsampled by 4, so that the JPEG/R encoder will require width to be 32 aligned, which is not ideal. We should handle widths that are 8 aligned but not 32 aligned.
Test: recoverymap_test
Bug: b/264715926
Change-Id: I74eaeec7c16f8f2621e72c067464897c8aba9d89
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
index ef5498c..eb557e5 100644
--- a/libs/jpegrecoverymap/recoverymap.cpp
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -25,6 +25,7 @@
#include <image_io/jpeg/jpeg_scanner.h>
#include <image_io/jpeg/jpeg_info_builder.h>
#include <image_io/base/data_segment_data_source.h>
+#include <utils/Log.h>
#include <memory>
#include <sstream>
@@ -61,6 +62,10 @@
// 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 compress quality (0 ~ 100) for recovery map
static const int kMapCompressQuality = 85;
@@ -256,6 +261,13 @@
return ERROR_JPEGR_INVALID_INPUT_TYPE;
}
+ 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;
+ }
+
jpegr_metadata metadata;
metadata.version = kJpegrVersion;
metadata.transferFunction = hdr_tf;
@@ -330,6 +342,13 @@
return ERROR_JPEGR_RESOLUTION_MISMATCH;
}
+ 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;
+ }
+
jpegr_metadata metadata;
metadata.version = kJpegrVersion;
metadata.transferFunction = hdr_tf;
@@ -395,6 +414,13 @@
return ERROR_JPEGR_RESOLUTION_MISMATCH;
}
+ 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;
+ }
+
jpegr_metadata metadata;
metadata.version = kJpegrVersion;
metadata.transferFunction = hdr_tf;
@@ -470,6 +496,13 @@
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;
+ }
+
JpegDecoder jpeg_decoder;
if (!jpeg_decoder.decompressImage(compressed_jpeg_image->data, compressed_jpeg_image->length)) {
return ERROR_JPEGR_DECODE_ERROR;
@@ -733,11 +766,14 @@
size_t image_height = uncompressed_yuv_420_image->height;
size_t map_width = image_width / kMapDimensionScaleFactor;
size_t map_height = image_height / kMapDimensionScaleFactor;
+ size_t map_stride = static_cast<size_t>(
+ floor((map_width + kJpegBlock - 1) / kJpegBlock)) * kJpegBlock;
+ size_t map_height_aligned = ((map_height + 1) >> 1) << 1;
- dest->width = map_width;
- dest->height = map_height;
+ dest->width = map_stride;
+ dest->height = map_height_aligned;
dest->colorGamut = JPEGR_COLORGAMUT_UNSPECIFIED;
- dest->data = new uint8_t[map_width * map_height];
+ dest->data = new uint8_t[map_stride * map_height_aligned];
std::unique_ptr<uint8_t[]> map_data;
map_data.reset(reinterpret_cast<uint8_t*>(dest->data));