Loading libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp +21 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } Loading libs/ultrahdr/include/ultrahdr/ultrahdr.h +2 −2 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 Loading libs/ultrahdr/jpegencoderhelper.cpp +64 −3 Original line number Diff line number Diff line Loading @@ -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: Loading Loading @@ -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; Loading @@ -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) { Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading libs/ultrahdr/jpegr.cpp +30 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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)); Loading Loading @@ -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, Loading Loading @@ -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(); Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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); Loading libs/ultrahdr/tests/jpegencoderhelper_test.cpp +1 −10 Original line number Diff line number Diff line Loading @@ -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)); } Loading Loading
libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp +21 −8 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } } } Loading
libs/ultrahdr/include/ultrahdr/ultrahdr.h +2 −2 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 Loading
libs/ultrahdr/jpegencoderhelper.cpp +64 −3 Original line number Diff line number Diff line Loading @@ -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: Loading Loading @@ -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; Loading @@ -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) { Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading
libs/ultrahdr/jpegr.cpp +30 −16 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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)); Loading Loading @@ -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, Loading Loading @@ -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(); Loading Loading @@ -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) { Loading @@ -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; Loading Loading @@ -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); Loading
libs/ultrahdr/tests/jpegencoderhelper_test.cpp +1 −10 Original line number Diff line number Diff line Loading @@ -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)); } Loading