Skip to content

Commit

Permalink
Improved encoding, improved decoding, added loseless chroma encoding …
Browse files Browse the repository at this point in the history
…mode
  • Loading branch information
awxkee committed Nov 30, 2024
1 parent de7bdd4 commit 5e7fb3b
Show file tree
Hide file tree
Showing 24 changed files with 456 additions and 1,240 deletions.
20 changes: 11 additions & 9 deletions app/src/main/java/com/radzivon/bartoshyk/avif/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,9 @@ class MainActivity : AppCompatActivity() {
var allFiles = mutableListOf<String>()
allFiles.addAll(allFiles2)
allFiles.addAll(allFiles1)
allFiles = allFiles.filter { it.contains("wide_gamut.avif") || it.contains("IMG_0199_rr.avif") || it.contains("bt_2020_pq.avif") }.toMutableList()
// allFiles = allFiles.filter { it.contains("wide_gamut.avif") || it.contains("IMG_0199_rr.avif") || it.contains("bt_2020_pq.avif") }.toMutableList()
// allFiles = allFiles.filter { it.contains("bbb_alpha_inverted.avif") }.toMutableList()
// allFiles = allFiles.filter { it.contains("bt_2020_pq.avif") }.toMutableList()
for (file in allFiles) {
try {
Log.d("AVIF", "start processing $file")
Expand All @@ -148,14 +149,15 @@ class MainActivity : AppCompatActivity() {

Log.d("AVIFFFF", "Decode time ${System.currentTimeMillis() - start}")

// val encode = coder.encodeAvif(bitmap0, avifChromaSubsampling = AvifChromaSubsampling.YUV400)
val encode = coder.encodeAvif(bitmap0, avifChromaSubsampling = AvifChromaSubsampling.YUV422)
val roundTripped = coder.decode(encode)
//
// val cachedFile = File(cacheDir, "yuv400.avif")
// FileOutputStream(cachedFile).use {
// val bf = it.sink().buffer()
// bf.write(encode)
// bf.flush()
// }
val cachedFile = File(cacheDir, "yuv400.avif")
FileOutputStream(cachedFile).use {
val bf = it.sink().buffer()
bf.write(encode)
bf.flush()
}
//
// val round = coder.decode(
// byteArray = encode,
Expand All @@ -170,7 +172,7 @@ class MainActivity : AppCompatActivity() {
binding.scrollViewContainer,
false
)
imageView.root.setImageBitmap(bitmap0)
imageView.root.setImageBitmap(roundTripped)
binding.scrollViewContainer.addView(imageView.root)
}
// lifecycleScope.launch(Dispatchers.Main) {
Expand Down
7 changes: 5 additions & 2 deletions avif-coder/src/main/cpp/AvifDecoderController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@ AvifImageFrame AvifDecoderController::getFrame(uint32_t frame,
throw std::runtime_error(str);
}

float intensityTarget =
decoder->image->clli.maxCLL == 0 ? 1000.0f : static_cast<float>(decoder->image->clli.maxCLL);

aligned_uint8_vector iccProfile(0);
if (decoder->image->icc.data && decoder->image->icc.size) {
iccProfile.resize(decoder->image->icc.size);
Expand Down Expand Up @@ -409,11 +412,11 @@ AvifImageFrame AvifDecoderController::getFrame(uint32_t frame,
forwardTrc,
TransferFunction::Srgb,
toneMapper,
coeffs);
coeffs, intensityTarget);
} else {
applyColorMatrix(reinterpret_cast<uint8_t *>(imageStore.data()), stride, imageWidth,
imageHeight, matrix, forwardTrc, TransferFunction::Srgb, toneMapper,
coeffs);
coeffs, intensityTarget);
}

}
Expand Down
2 changes: 1 addition & 1 deletion avif-coder/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ add_library(coder SHARED JniEncoder.cpp JniException.cpp SizeScaler.cpp
colorspace/Rec2408ToneMapper.cpp colorspace/LogarithmicToneMapper.cpp
colorspace/ColorMatrix.cpp imagebits/ScanAlpha.cpp imagebits/Rgba16.cpp
AvifDecoderController.cpp HeifImageDecoder.cpp JniAnimatedController.cpp
colorspace/FilmicToneMapper.cpp)
colorspace/FilmicToneMapper.cpp colorspace/AcesToneMapper.cpp)

add_library(libheif SHARED IMPORTED)
add_library(libyuv STATIC IMPORTED)
Expand Down
14 changes: 12 additions & 2 deletions avif-coder/src/main/cpp/HeifImageDecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ AvifImageFrame HeifImageDecoder::getFrame(std::vector<uint8_t> &srcBuffer,
heif_image_release(im);
});

float intensityTarget = 1000.0f;

if (heif_image_has_content_light_level(img.get())) {
heif_content_light_level light_level = {0};
heif_image_get_content_light_level(img.get(), &light_level);
if (light_level.max_content_light_level != 0) {
intensityTarget = light_level.max_content_light_level;
}
}

std::vector<uint8_t> profile;
std::string colorProfile;

Expand Down Expand Up @@ -231,11 +241,11 @@ AvifImageFrame HeifImageDecoder::getFrame(std::vector<uint8_t> &srcBuffer,
forwardTrc,
TransferFunction::Srgb,
toneMapper,
coeffs);
coeffs, intensityTarget);
} else {
applyColorMatrix(reinterpret_cast<uint8_t *>(dstARGB.data()), stride, imageWidth,
imageHeight, matrix, forwardTrc, TransferFunction::Srgb, toneMapper,
coeffs);
coeffs, intensityTarget);
}
}

Expand Down
39 changes: 26 additions & 13 deletions avif-coder/src/main/cpp/JniEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "avif/avif_cxx.h"
#include <libyuv.h>
#include "AvifDecoderController.h"
#include "avifweaver.h"

using namespace std;

Expand All @@ -74,7 +75,8 @@ enum AvifChromaSubsampling {
AVIF_CHROMA_YUV_420,
AVIF_CHROMA_YUV_422,
AVIF_CHROMA_YUV_444,
AVIF_CHROMA_YUV_400
AVIF_CHROMA_YUV_400,
AVIF_CHROMA_LOSELESS
};

struct heif_error writeHeifData(struct heif_context *ctx,
Expand Down Expand Up @@ -319,7 +321,7 @@ jbyteArray encodeBitmapHevc(JNIEnv *env,
vStride,
info.width,
info.height,
profile->full_range_flag ? YuvRange::Full : YuvRange::Tv,
profile->full_range_flag ? YuvRange::Pc : YuvRange::Tv,
matrix);

if (nclxResult) {
Expand Down Expand Up @@ -456,10 +458,17 @@ jbyteArray encodeBitmapAvif(JNIEnv *env,
}
} else if (preferredChromaSubsampling == AvifChromaSubsampling::AVIF_CHROMA_YUV_422) {
pixelFormat = avifPixelFormat::AVIF_PIXEL_FORMAT_YUV422;
} else if (preferredChromaSubsampling == AvifChromaSubsampling::AVIF_CHROMA_YUV_444) {
} else if (preferredChromaSubsampling == AvifChromaSubsampling::AVIF_CHROMA_YUV_444
|| preferredChromaSubsampling == AvifChromaSubsampling::AVIF_CHROMA_LOSELESS) {
pixelFormat = avifPixelFormat::AVIF_PIXEL_FORMAT_YUV444;
} else if (preferredChromaSubsampling == AvifChromaSubsampling::AVIF_CHROMA_YUV_400) {
pixelFormat = avifPixelFormat::AVIF_PIXEL_FORMAT_YUV400;
} else if (preferredChromaSubsampling == AvifChromaSubsampling::AVIF_CHROMA_YUV_420) {
pixelFormat = avifPixelFormat::AVIF_PIXEL_FORMAT_YUV420;
} else {
std::string str = "Unknown chroma subsampling";
throwException(env, str);
return static_cast<jbyteArray>(nullptr);
}
avif::ImagePtr image(avifImageCreate(info.width, info.height, 8, pixelFormat));

Expand Down Expand Up @@ -595,7 +604,7 @@ jbyteArray encodeBitmapAvif(JNIEnv *env,
vStride,
info.width,
info.height,
yuvRange == AVIF_RANGE_FULL ? YuvRange::Full : YuvRange::Tv,
yuvRange == AVIF_RANGE_FULL ? YuvRange::Pc : YuvRange::Tv,
matrix);
} else if (pixelFormat == AVIF_PIXEL_FORMAT_YUV422) {
RgbaToYuv422(imageStore.data(),
Expand All @@ -608,9 +617,13 @@ jbyteArray encodeBitmapAvif(JNIEnv *env,
vStride,
info.width,
info.height,
yuvRange == AVIF_RANGE_FULL ? YuvRange::Full : YuvRange::Tv,
yuvRange == AVIF_RANGE_FULL ? YuvRange::Pc : YuvRange::Tv,
matrix);
} else if (pixelFormat == AVIF_PIXEL_FORMAT_YUV444) {
if (preferredChromaSubsampling == AvifChromaSubsampling::AVIF_CHROMA_LOSELESS) {
matrix = YuvMatrix::Identity;
yuvRange = AVIF_RANGE_FULL;
}
RgbaToYuv444(imageStore.data(),
stride,
yPlane,
Expand All @@ -621,7 +634,7 @@ jbyteArray encodeBitmapAvif(JNIEnv *env,
vStride,
info.width,
info.height,
yuvRange == AVIF_RANGE_FULL ? YuvRange::Full : YuvRange::Tv,
yuvRange == AVIF_RANGE_FULL ? YuvRange::Pc : YuvRange::Tv,
matrix);
} else if (pixelFormat == AVIF_PIXEL_FORMAT_YUV400) {
RgbaToYuv400(imageStore.data(),
Expand All @@ -630,17 +643,17 @@ jbyteArray encodeBitmapAvif(JNIEnv *env,
yStride,
info.width,
info.height,
yuvRange == AVIF_RANGE_FULL ? YuvRange::Full : YuvRange::Tv,
yuvRange == AVIF_RANGE_FULL ? YuvRange::Pc : YuvRange::Tv,
matrix);
}

image->matrixCoefficients = matrixCoefficients;
image->colorPrimaries = colorPrimaries;
image->transferCharacteristics = transferCharacteristics;
image->yuvRange = yuvRange;

if (nclxResult) {
if (iccProfile.empty()) {
image->matrixCoefficients = matrixCoefficients;
image->colorPrimaries = colorPrimaries;
image->transferCharacteristics = transferCharacteristics;
image->yuvRange = yuvRange;
} else {
if (!iccProfile.empty()) {
result = avifImageSetProfileICC(image.get(), iccProfile.data(), iccProfile.size());
if (result != AVIF_RESULT_OK) {
std::string str = "Can't set required color profile";
Expand Down
Loading

0 comments on commit 5e7fb3b

Please sign in to comment.