Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68ecaf72 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 10252918 from 7fbf5f1a to udc-release

Change-Id: I63d8e17ae5af16eda60c95054dd8677d7ff85284
parents 1bdc9c3d 7fbf5f1a
Loading
Loading
Loading
Loading
+21 −8
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ const int kCgMax = ULTRAHDR_COLORGAMUT_MAX;

// Transfer functions for image data, sync with ultrahdr.h
const int kTfMin = ULTRAHDR_TF_UNSPECIFIED + 1;
const int kTfMax = ULTRAHDR_TF_MAX;
const int kTfMax = ULTRAHDR_TF_PQ;

// Transfer functions for image data, sync with ultrahdr.h
const int kOfMin = ULTRAHDR_OUTPUT_UNSPECIFIED + 1;
@@ -265,16 +265,29 @@ void JpegHDRFuzzer::process() {
            }
        }
        if (status == android::OK) {
            jpegr_uncompressed_struct decodedJpegR;
            auto decodedRaw = std::make_unique<uint8_t[]>(width * height * 8);
            decodedJpegR.data = decodedRaw.get();
            jpegHdr.decodeJPEGR(&jpegImgR, &decodedJpegR,
                                mFdp.ConsumeFloatingPointInRange<float>(1.0, FLT_MAX), nullptr, of,
                                nullptr, nullptr);
            std::vector<uint8_t> iccData(0);
            std::vector<uint8_t> exifData(0);
            jpegr_info_struct info{0, 0, &iccData, &exifData};
            jpegHdr.getJPEGRInfo(&jpegImgR, &info);
            status = jpegHdr.getJPEGRInfo(&jpegImgR, &info);
            if (status == android::OK) {
                size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_SDR) ? 4 : 8);
                jpegr_uncompressed_struct decodedJpegR;
                auto decodedRaw = std::make_unique<uint8_t[]>(outSize);
                decodedJpegR.data = decodedRaw.get();
                ultrahdr_metadata_struct metadata;
                jpegr_uncompressed_struct decodedGainMap{};
                status = jpegHdr.decodeJPEGR(&jpegImgR, &decodedJpegR,
                                             mFdp.ConsumeFloatingPointInRange<float>(1.0, FLT_MAX),
                                             nullptr, of, &decodedGainMap, &metadata);
                if (status != android::OK) {
                    ALOGE("encountered error during decoding %d", status);
                }
                if (decodedGainMap.data) free(decodedGainMap.data);
            } else {
                ALOGE("encountered error during get jpeg info %d", status);
            }
        } else {
            ALOGE("encountered error during encoding %d", status);
        }
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@
namespace android::ultrahdr {
// Color gamuts for image data
typedef enum {
  ULTRAHDR_COLORGAMUT_UNSPECIFIED,
  ULTRAHDR_COLORGAMUT_UNSPECIFIED = -1,
  ULTRAHDR_COLORGAMUT_BT709,
  ULTRAHDR_COLORGAMUT_P3,
  ULTRAHDR_COLORGAMUT_BT2100,
@@ -52,7 +52,7 @@ typedef enum {
 */
struct ultrahdr_metadata_struct {
  // Ultra HDR library version
  const char* version;
  std::string version;
  // Max Content Boost for the map
  float maxContentBoost;
  // Min Content Boost for the map
+64 −3
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@

namespace android::ultrahdr {

#define ALIGNM(x, m)  ((((x) + ((m) - 1)) / (m)) * (m))

// The destination manager that can access |mResultBuffer| in JpegEncoderHelper.
struct destination_mgr {
public:
@@ -175,6 +177,37 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t*
    std::unique_ptr<uint8_t[]> empty(new 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);
    std::unique_ptr<uint8_t[]> buffer_intrm = nullptr;
    uint8_t* y_plane_intrm = nullptr;
    uint8_t* u_plane_intrm = nullptr;
    uint8_t* v_plane_intrm = nullptr;
    JSAMPROW y_intrm[kCompressBatchSize];
    JSAMPROW cb_intrm[kCompressBatchSize / 2];
    JSAMPROW cr_intrm[kCompressBatchSize / 2];
    JSAMPARRAY planes_intrm[3]{y_intrm, cb_intrm, cr_intrm};
    if (!is_width_aligned) {
        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();
        u_plane_intrm = y_plane_intrm + (aligned_width * kCompressBatchSize);
        v_plane_intrm = u_plane_intrm + (aligned_width * kCompressBatchSize) / 4;
        for (int i = 0; i < kCompressBatchSize; ++i) {
            y_intrm[i] = y_plane_intrm + i * aligned_width;
            memset(y_intrm[i] + cinfo->image_width, 0, aligned_width - cinfo->image_width);
        }
        for (int i = 0; i < kCompressBatchSize / 2; ++i) {
            int offset_intrm = i * (aligned_width / 2);
            cb_intrm[i] = u_plane_intrm + offset_intrm;
            cr_intrm[i] = v_plane_intrm + offset_intrm;
            memset(cb_intrm[i] + cinfo->image_width / 2, 0,
                   (aligned_width - cinfo->image_width) / 2);
            memset(cr_intrm[i] + cinfo->image_width / 2, 0,
                   (aligned_width - cinfo->image_width) / 2);
        }
    }

    while (cinfo->next_scanline < cinfo->image_height) {
        for (int i = 0; i < kCompressBatchSize; ++i) {
            size_t scanline = cinfo->next_scanline + i;
@@ -183,6 +216,9 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t*
            } else {
                y[i] = empty.get();
            }
            if (!is_width_aligned) {
                memcpy(y_intrm[i], y[i], cinfo->image_width);
            }
        }
        // cb, cr only have half scanlines
        for (int i = 0; i < kCompressBatchSize / 2; ++i) {
@@ -194,9 +230,13 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t*
            } else {
                cb[i] = cr[i] = empty.get();
            }
            if (!is_width_aligned) {
                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, planes, kCompressBatchSize);
        }
        int processed = jpeg_write_raw_data(cinfo, is_width_aligned ? planes : planes_intrm,
                                            kCompressBatchSize);
        if (processed != kCompressBatchSize) {
            ALOGE("Number of processed lines does not equal input lines.");
            return false;
@@ -213,6 +253,23 @@ bool JpegEncoderHelper::compressSingleChannel(jpeg_compress_struct* cinfo, const
    std::unique_ptr<uint8_t[]> empty(new 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);
    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) {
        size_t mcu_row_size = aligned_width * kCompressBatchSize;
        buffer_intrm = std::make_unique<uint8_t[]>(mcu_row_size);
        y_plane_intrm = buffer_intrm.get();
        for (int i = 0; i < kCompressBatchSize; ++i) {
            y_intrm[i] = y_plane_intrm + i * aligned_width;
            memset(y_intrm[i] + cinfo->image_width, 0, aligned_width - cinfo->image_width);
        }
    }

    while (cinfo->next_scanline < cinfo->image_height) {
        for (int i = 0; i < kCompressBatchSize; ++i) {
            size_t scanline = cinfo->next_scanline + i;
@@ -221,8 +278,12 @@ bool JpegEncoderHelper::compressSingleChannel(jpeg_compress_struct* cinfo, const
            } else {
                y[i] = empty.get();
            }
            if (!is_width_aligned) {
                memcpy(y_intrm[i], y[i], cinfo->image_width);
            }
        }
        int processed = jpeg_write_raw_data(cinfo, planes, kCompressBatchSize);
        int processed = jpeg_write_raw_data(cinfo, is_width_aligned ? planes : planes_intrm,
                                            kCompressBatchSize);
        if (processed != kCompressBatchSize / 2) {
            ALOGE("Number of processed lines does not equal input lines.");
            return false;
+30 −16
Original line number Diff line number Diff line
@@ -76,9 +76,9 @@ static const int kMinHeight = 2 * kMapDimensionScaleFactor;
// 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.
// If this criteria is not facilitated, we will pad zeros based to each line 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;

@@ -145,7 +145,8 @@ status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr uncompressed_p010_ima
    return ERROR_JPEGR_INVALID_NULL_PTR;
  }

  if (hdr_tf <= ULTRAHDR_TF_UNSPECIFIED || hdr_tf > ULTRAHDR_TF_MAX) {
  if (hdr_tf <= ULTRAHDR_TF_UNSPECIFIED || hdr_tf > ULTRAHDR_TF_MAX
          || hdr_tf == ULTRAHDR_TF_SRGB) {
    ALOGE("Invalid hdr transfer function %d", hdr_tf);
    return ERROR_JPEGR_INVALID_INPUT_TYPE;
  }
@@ -228,13 +229,8 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
  metadata.version = kJpegrVersion;

  jpegr_uncompressed_struct uncompressed_yuv_420_image;
  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);
  unique_ptr<uint8_t[]> uncompressed_yuv_420_image_data = make_unique<uint8_t[]>(
      uncompressed_p010_image->width * uncompressed_p010_image->height * 3 / 2);
  uncompressed_yuv_420_image.data = uncompressed_yuv_420_image_data.get();
  JPEGR_CHECK(toneMap(uncompressed_p010_image, &uncompressed_yuv_420_image));

@@ -509,11 +505,6 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
    return ERROR_JPEGR_INVALID_INPUT_TYPE;
  }

  if (gain_map != nullptr && gain_map->data == nullptr) {
    ALOGE("received nullptr address for gain map data");
    return ERROR_JPEGR_INVALID_INPUT_TYPE;
  }

  if (output_format == ULTRAHDR_OUTPUT_SDR) {
    JpegDecoderHelper jpeg_decoder;
    if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length,
@@ -555,6 +546,11 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
  if (!gain_map_decoder.decompressImage(compressed_map.data, compressed_map.length)) {
    return ERROR_JPEGR_DECODE_ERROR;
  }
  if ((gain_map_decoder.getDecompressedImageWidth() *
       gain_map_decoder.getDecompressedImageHeight()) >
      gain_map_decoder.getDecompressedImageSize()) {
    return ERROR_JPEGR_CALCULATION_ERROR;
  }

  if (gain_map != nullptr) {
    gain_map->width = gain_map_decoder.getDecompressedImageWidth();
@@ -584,6 +580,11 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
  if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length)) {
    return ERROR_JPEGR_DECODE_ERROR;
  }
  if ((jpeg_decoder.getDecompressedImageWidth() *
       jpeg_decoder.getDecompressedImageHeight() * 3 / 2) >
      jpeg_decoder.getDecompressedImageSize()) {
    return ERROR_JPEGR_CALCULATION_ERROR;
  }

  if (exif != nullptr) {
    if (exif->data == nullptr) {
@@ -605,7 +606,6 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
  uncompressed_yuv_420_image.data = jpeg_decoder.getDecompressedImagePtr();
  uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth();
  uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight();

  JPEGR_CHECK(applyGainMap(&uncompressed_yuv_420_image, &map, &uhdr_metadata, output_format,
                           max_display_boost, dest));
  return NO_ERROR;
@@ -848,6 +848,20 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image,
    return ERROR_JPEGR_INVALID_NULL_PTR;
  }

  // TODO: remove once map scaling factor is computed based on actual map dims
  size_t image_width = uncompressed_yuv_420_image->width;
  size_t image_height = uncompressed_yuv_420_image->height;
  size_t map_width = image_width / kMapDimensionScaleFactor;
  size_t map_height = image_height / kMapDimensionScaleFactor;
  map_width = static_cast<size_t>(
          floor((map_width + kJpegBlock - 1) / kJpegBlock)) * kJpegBlock;
  map_height = ((map_height + 1) >> 1) << 1;
  if (map_width != uncompressed_gain_map->width
   || map_height != uncompressed_gain_map->height) {
    ALOGE("gain map dimensions and primary image dimensions are not to scale");
    return ERROR_JPEGR_INVALID_INPUT_TYPE;
  }

  dest->width = uncompressed_yuv_420_image->width;
  dest->height = uncompressed_yuv_420_image->height;
  ShepardsIDW idwTable(kMapDimensionScaleFactor);
+1 −10
Original line number Diff line number Diff line
@@ -108,18 +108,9 @@ TEST_F(JpegEncoderHelperTest, encodeAlignedImage) {
    ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0));
}

// The width of the "unaligned" image is not 16-aligned, and will fail if encoded directly.
// Should pass with the padding zero method.
TEST_F(JpegEncoderHelperTest, encodeUnalignedImage) {
    JpegEncoderHelper encoder;
    const size_t paddingZeroLength = JpegEncoderHelper::kCompressBatchSize
            * JpegEncoderHelper::kCompressBatchSize / 4;
    std::unique_ptr<uint8_t[]> imageWithPaddingZeros(
            new uint8_t[UNALIGNED_IMAGE_WIDTH * UNALIGNED_IMAGE_HEIGHT * 3 / 2
            + paddingZeroLength]);
    memcpy(imageWithPaddingZeros.get(), mUnalignedImage.buffer.get(),
            UNALIGNED_IMAGE_WIDTH * UNALIGNED_IMAGE_HEIGHT * 3 / 2);
    EXPECT_TRUE(encoder.compressImage(imageWithPaddingZeros.get(), mUnalignedImage.width,
    EXPECT_TRUE(encoder.compressImage(mUnalignedImage.buffer.get(), mUnalignedImage.width,
                                      mUnalignedImage.height, JPEG_QUALITY, NULL, 0));
    ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0));
}