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

Commit 66ca6e39 authored by Dichen Zhang's avatar Dichen Zhang
Browse files

JPEG/R: stride support

Bug: 264715926
Test: jpegr_test.cpp, manual test with camera/display app
Change-Id: I92c1d19b8bd49060794b4a9427c67017aa6743a9
parent 2493d122
Loading
Loading
Loading
Loading
+26 −2
Original line number Diff line number Diff line
@@ -59,12 +59,26 @@ struct jpegr_info_struct {
struct jpegr_uncompressed_struct {
    // Pointer to the data location.
    void* data;
    // Width of the recovery map or image in pixels.
    // Width of the recovery map or the luma plane of the image in pixels.
    int width;
    // Height of the recovery map or image in pixels.
    // Height of the recovery map or the luma plane of the image in pixels.
    int height;
    // Color gamut.
    jpegr_color_gamut colorGamut;

    // Values below are optional
    // Pointer to chroma data, if it's NULL, chroma plane is considered to be immediately
    // following after the luma plane.
    // Note: currently this feature is only supported for P010 image (HDR input).
    void* chroma_data = nullptr;
    // Strides of Y plane in number of pixels, using 0 to present uninitialized, must be
    // larger than or equal to luma width.
    // Note: currently this feature is only supported for P010 image (HDR input).
    int luma_stride = 0;
    // Strides of UV plane in number of pixels, using 0 to present uninitialized, must be
    // larger than or equal to chroma width.
    // Note: currently this feature is only supported for P010 image (HDR input).
    int chroma_stride = 0;
};

/*
@@ -358,6 +372,16 @@ private:
     */
    status_t toneMap(jr_uncompressed_ptr src,
                     jr_uncompressed_ptr dest);

    /*
     * This method will check the validity of the input images.
     *
     * @param uncompressed_p010_image uncompressed HDR image in P010 color format
     * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format
     * @return NO_ERROR if the input images are valid, error code is not valid.
     */
    status_t areInputImagesValid(jr_uncompressed_ptr uncompressed_p010_image,
                                 jr_uncompressed_ptr uncompressed_yuv_420_image);
};

} // namespace android::jpegrecoverymap
+2 −0
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ enum {
    ERROR_JPEGR_CALCULATION_ERROR       = JPEGR_RUNTIME_ERROR_BASE - 3,
    ERROR_JPEGR_METADATA_ERROR          = JPEGR_RUNTIME_ERROR_BASE - 4,
    ERROR_JPEGR_TONEMAP_ERROR           = JPEGR_RUNTIME_ERROR_BASE - 5,

    ERROR_JPEGR_UNSUPPORTED_FEATURE     = -20000,
};

}  // namespace android::jpegrecoverymap
+92 −44
Original line number Diff line number Diff line
@@ -86,6 +86,54 @@ int GetCPUCoreCount() {
  return cpuCoreCount;
}

status_t JpegR::areInputImagesValid(jr_uncompressed_ptr uncompressed_p010_image,
                                    jr_uncompressed_ptr uncompressed_yuv_420_image) {
  if (uncompressed_p010_image == nullptr) {
    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",
                uncompressed_p010_image->luma_stride, uncompressed_p010_image->width);
    return ERROR_JPEGR_INVALID_INPUT_TYPE;
  }

  if (uncompressed_yuv_420_image == nullptr) {
    return NO_ERROR;
  }

  if (uncompressed_yuv_420_image->luma_stride != 0) {
    ALOGE("Stride is not supported for YUV420 image");
    return ERROR_JPEGR_UNSUPPORTED_FEATURE;
  }

  if (uncompressed_yuv_420_image->chroma_data != nullptr) {
    ALOGE("Pointer to chroma plane is not supported for YUV420 image, chroma data must"
          "be immediately after the luma data.");
    return ERROR_JPEGR_UNSUPPORTED_FEATURE;
  }

  if (uncompressed_p010_image->width != uncompressed_yuv_420_image->width
      || uncompressed_p010_image->height != uncompressed_yuv_420_image->height) {
    ALOGE("Image resolutions mismatch: P010: %dx%d, YUV420: %dx%d",
              uncompressed_p010_image->width,
              uncompressed_p010_image->height,
              uncompressed_yuv_420_image->width,
              uncompressed_yuv_420_image->height);
    return ERROR_JPEGR_RESOLUTION_MISMATCH;
  }

  return NO_ERROR;
}

/* Encode API-0 */
status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
                            jpegr_transfer_function hdr_tf,
@@ -100,11 +148,9 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
    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;
  if (status_t ret = areInputImagesValid(
          uncompressed_p010_image, /* uncompressed_yuv_420_image */ nullptr) != NO_ERROR) {
    return ret;
  }

  jpegr_metadata_struct metadata;
@@ -164,16 +210,9 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
    return ERROR_JPEGR_INVALID_INPUT_TYPE;
  }

  if (uncompressed_p010_image->width != uncompressed_yuv_420_image->width
   || uncompressed_p010_image->height != uncompressed_yuv_420_image->height) {
    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;
  if (status_t ret = areInputImagesValid(
          uncompressed_p010_image, uncompressed_yuv_420_image) != NO_ERROR) {
    return ret;
  }

  jpegr_metadata_struct metadata;
@@ -223,16 +262,9 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
    return ERROR_JPEGR_INVALID_NULL_PTR;
  }

  if (uncompressed_p010_image->width != uncompressed_yuv_420_image->width
   || uncompressed_p010_image->height != uncompressed_yuv_420_image->height) {
    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;
  if (status_t ret = areInputImagesValid(
          uncompressed_p010_image, uncompressed_yuv_420_image) != NO_ERROR) {
    return ret;
  }

  jpegr_metadata_struct metadata;
@@ -266,11 +298,9 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
    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 (status_t ret = areInputImagesValid(
          uncompressed_p010_image, /* uncompressed_yuv_420_image */ nullptr) != NO_ERROR) {
    return ret;
  }

  JpegDecoderHelper jpeg_decoder;
@@ -993,25 +1023,43 @@ status_t JpegR::toneMap(jr_uncompressed_ptr src, jr_uncompressed_ptr dest) {
    return ERROR_JPEGR_INVALID_NULL_PTR;
  }

  size_t src_luma_stride = src->luma_stride;
  size_t src_chroma_stride = src->chroma_stride;
  uint16_t* src_luma_data = reinterpret_cast<uint16_t*>(src->data);
  uint16_t* src_chroma_data = reinterpret_cast<uint16_t*>(src->chroma_data);

  if (src_chroma_data == nullptr) {
    src_chroma_data = &reinterpret_cast<uint16_t*>(src->data)[src->luma_stride * src->height];
  }
  if (src_luma_stride == 0) {
    src_luma_stride = src->width;
  }
  if (src_chroma_stride == 0) {
    src_chroma_stride = src_luma_stride;
  }

  dest->width = src->width;
  dest->height = src->height;

  size_t pixel_count = src->width * src->height;
  size_t dest_luma_pixel_count = dest->width * dest->height;

  for (size_t y = 0; y < src->height; ++y) {
    for (size_t x = 0; x < src->width; ++x) {
      size_t pixel_y_idx = x + y * src->width;
      size_t pixel_uv_idx = x / 2 + (y / 2) * (src->width / 2);

      uint16_t y_uint = reinterpret_cast<uint16_t*>(src->data)[pixel_y_idx]
                        >> 6;
      uint16_t u_uint = reinterpret_cast<uint16_t*>(src->data)[pixel_count + pixel_uv_idx * 2]
                        >> 6;
      uint16_t v_uint = reinterpret_cast<uint16_t*>(src->data)[pixel_count + pixel_uv_idx * 2 + 1]
                        >> 6;

      uint8_t* y = &reinterpret_cast<uint8_t*>(dest->data)[pixel_y_idx];
      uint8_t* u = &reinterpret_cast<uint8_t*>(dest->data)[pixel_count + pixel_uv_idx];
      uint8_t* v = &reinterpret_cast<uint8_t*>(dest->data)[pixel_count * 5 / 4 + pixel_uv_idx];
      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_luma_data[src_y_idx] >> 6;
      uint16_t u_uint = src_chroma_data[src_u_idx] >> 6;
      uint16_t v_uint = src_chroma_data[src_v_idx] >> 6;

      size_t dest_y_idx = x + y * dest->width;
      size_t dest_uv_idx = x / 2 + (y / 2) * (dest->width / 2);

      uint8_t* y = &reinterpret_cast<uint8_t*>(dest->data)[dest_y_idx];
      uint8_t* u = &reinterpret_cast<uint8_t*>(dest->data)[dest_luma_pixel_count + dest_uv_idx];
      uint8_t* v = &reinterpret_cast<uint8_t*>(
              dest->data)[dest_luma_pixel_count * 5 / 4 + dest_uv_idx];

      *y = static_cast<uint8_t>((y_uint >> 2) & 0xff);
      *u = static_cast<uint8_t>((u_uint >> 2) & 0xff);
+20 −9
Original line number Diff line number Diff line
@@ -493,17 +493,28 @@ Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y) {
}

Color getP010Pixel(jr_uncompressed_ptr image, size_t x, size_t y) {
  size_t pixel_count = image->width * image->height;
  size_t luma_stride = image->luma_stride;
  size_t chroma_stride = image->chroma_stride;
  uint16_t* luma_data = reinterpret_cast<uint16_t*>(image->data);
  uint16_t* chroma_data = reinterpret_cast<uint16_t*>(image->chroma_data);

  size_t pixel_y_idx = x + y * image->width;
  size_t pixel_uv_idx = x / 2 + (y / 2) * (image->width / 2);
  if (luma_stride == 0) {
    luma_stride = image->width;
  }
  if (chroma_stride == 0) {
    chroma_stride = luma_stride;
  }
  if (chroma_data == nullptr) {
    chroma_data = &reinterpret_cast<uint16_t*>(image->data)[image->luma_stride * image->height];
  }

  size_t pixel_y_idx = y * luma_stride + x;
  size_t pixel_u_idx = (y >> 1) * chroma_stride + (x & ~0x1);
  size_t pixel_v_idx = pixel_u_idx + 1;

  uint16_t y_uint = reinterpret_cast<uint16_t*>(image->data)[pixel_y_idx]
                  >> 6;
  uint16_t u_uint = reinterpret_cast<uint16_t*>(image->data)[pixel_count + pixel_uv_idx * 2]
                  >> 6;
  uint16_t v_uint = reinterpret_cast<uint16_t*>(image->data)[pixel_count + pixel_uv_idx * 2 + 1]
                  >> 6;
  uint16_t y_uint = luma_data[pixel_y_idx] >> 6;
  uint16_t u_uint = chroma_data[pixel_u_idx] >> 6;
  uint16_t v_uint = chroma_data[pixel_v_idx] >> 6;

  // Conversions include taking narrow-range into account.
  return {{{ (static_cast<float>(y_uint) - 64.0f) / 876.0f,
+2.65 MiB

File added.

No diff preview for this file type.

Loading