Skip to content

Commit 54676b5

Browse files
committed
Fix non-continious memory allocation + F16 encoding
1 parent cd6aa82 commit 54676b5

File tree

4 files changed

+78
-32
lines changed

4 files changed

+78
-32
lines changed

app/src/main/java/com/radzivon/bartoshyk/avif/MainActivity.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class MainActivity : AppCompatActivity() {
3636

3737
// Example of a call to a native method
3838
//
39-
val buffer = this.assets.open("test_1.avif").source().buffer().readByteArray()
39+
val buffer = this.assets.open("hato-wide-gamut.avif").source().buffer().readByteArray()
4040
// assert(HeifCoder().isAvif(buffer))
4141
val size = HeifCoder().getSize(buffer)!!
4242
val bitmap = HeifCoder().decodeSampled(buffer, size.width / 3, size.height / 3)
@@ -46,7 +46,7 @@ class MainActivity : AppCompatActivity() {
4646
// opts.inPreferredConfig = Bitmap.Config.RGBA_F16
4747
// }
4848
binding.imageView.setImageBitmap(bitmap)
49-
val encoded = HeifCoder().encodeAvif(bitmap)
49+
val encoded = HeifCoder().encodeHeic(bitmap)
5050
val decodedSample = HeifCoder().decode(encoded)
5151
binding.imageView.setImageBitmap(decodedSample)
5252

avif-coder/src/main/cpp/coder.cpp

+74-28
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
#include "android/bitmap.h"
66
#include "libyuv/convert_argb.h"
77
#include <vector>
8-
#include <float.h>
9-
#include <arm_fp16.h>
108
#include "jni_exception.h"
119
#include "scaler.h"
1210
#include <android/log.h>
@@ -28,6 +26,30 @@ int androidOSVersion() {
2826
return android_get_device_api_level();
2927
}
3028

29+
void
30+
copyRGBA16(std::shared_ptr<uint8_t> &source, int srcStride, uint8_t *destination, int dstStride,
31+
int width, int height) {
32+
auto src = reinterpret_cast<uint8_t *>(source.get());
33+
auto dst = reinterpret_cast<uint8_t *>(destination);
34+
35+
for (int y = 0; y < height; ++y) {
36+
37+
auto srcPtr = reinterpret_cast<uint16_t *>(src);
38+
auto dstPtr = reinterpret_cast<uint16_t *>(dst);
39+
40+
for (int x = 0; x < width; ++x) {
41+
auto srcPtr64 = reinterpret_cast<uint64_t *>(srcPtr);
42+
auto dstPtr64 = reinterpret_cast<uint64_t *>(dstPtr);
43+
dstPtr64[0] = srcPtr64[0];
44+
srcPtr += 4;
45+
dstPtr += 4;
46+
}
47+
48+
src += srcStride;
49+
dst += dstStride;
50+
}
51+
}
52+
3153
struct heif_error writeHeifData(struct heif_context *ctx,
3254
const void *data,
3355
size_t size,
@@ -131,8 +153,8 @@ jbyteArray encodeBitmap(JNIEnv *env, jobject thiz,
131153
uint8_t *imgData = heif_image_get_plane(image, heif_channel_interleaved, &stride);
132154
if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
133155
libyuv::ARGBCopy(sourceData.data(), (int) info.stride,
134-
imgData,
135-
stride, (int) info.width, (int) info.height);
156+
imgData,
157+
stride, (int) info.width, (int) info.height);
136158
} else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {
137159
libyuv::RGB565ToARGB(sourceData.data(), (int) info.stride, imgData,
138160
stride, (int) info.width, (int) info.height);
@@ -167,7 +189,7 @@ jbyteArray encodeBitmap(JNIEnv *env, jobject thiz,
167189
std::shared_ptr<char> dstARGB(
168190
static_cast<char *>(malloc(info.width * info.height * 4 * sizeof(uint16_t))),
169191
[](char *f) { free(f); });
170-
auto *srcData = reinterpret_cast<uint8_t *>(sourceData.data());
192+
auto srcData = reinterpret_cast<uint8_t *>(sourceData.data());
171193
uint16_t tmpR;
172194
uint16_t tmpG;
173195
uint16_t tmpB;
@@ -177,16 +199,14 @@ jbyteArray encodeBitmap(JNIEnv *env, jobject thiz,
177199
int dstStride = (int) info.width * 4 * (int) sizeof(uint16_t);
178200

179201
for (int y = 0; y < info.height; ++y) {
180-
181202
auto srcPtr = reinterpret_cast<uint16_t *>(srcData);
182203
auto dstPtr = reinterpret_cast<uint16_t *>(data64Ptr);
183-
184204
for (int x = 0; x < info.width; ++x) {
185205
auto alpha = half_to_float(srcPtr[3]);
186-
tmpR = (uint16_t) (half_to_float(srcPtr[0]) / scale);
187-
tmpG = (uint16_t) (half_to_float(srcPtr[1]) / scale);
188-
tmpB = (uint16_t) (half_to_float(srcPtr[2]) / scale);
189-
tmpA = (uint16_t) (alpha / scale);
206+
tmpR = (uint16_t) fmin(fmax((half_to_float(srcPtr[0]) / scale), 0), 1023);
207+
tmpG = (uint16_t) fmin(fmax((half_to_float(srcPtr[1]) / scale), 0), 1023);
208+
tmpB = (uint16_t) fmin(fmax((half_to_float(srcPtr[2]) / scale), 0), 1023);
209+
tmpA = (uint16_t) fmin(fmax((alpha / scale), 0), 1023);
190210

191211
dstPtr[0] = tmpR;
192212
dstPtr[1] = tmpG;
@@ -214,25 +234,37 @@ jbyteArray encodeBitmap(JNIEnv *env, jobject thiz,
214234
std::shared_ptr<char> dstARGB(
215235
static_cast<char *>(malloc(info.width * info.height * 4 * sizeof(uint8_t))),
216236
[](char *f) { free(f); });
217-
auto *srcData = reinterpret_cast<float16_t *>(sourceData.data());
237+
auto srcData = reinterpret_cast<uint8_t *>(sourceData.data());
218238
char tmpR;
219239
char tmpG;
220240
char tmpB;
221241
char tmpA;
222-
auto *data64Ptr = reinterpret_cast<uint32_t *>(dstARGB.get());
223-
const float maxColors = (float) pow(2.0, 8) - 1;
224-
for (int i = 0, k = 0; i < std::min(info.stride * info.height,
225-
info.width * info.height * 4); i += 4, k += 1) {
226-
tmpR = (char) (srcData[i] * maxColors);
227-
tmpG = (char) (srcData[i + 1] * maxColors);
228-
tmpB = (char) (srcData[i + 2] * maxColors);
229-
tmpA = (char) (srcData[i + 3] * maxColors);
230-
uint32_t color =
231-
((uint32_t) tmpA & 0xff) << 24 | ((uint32_t) tmpB & 0xff) << 16 |
232-
((uint32_t) tmpG & 0xff) << 8 | ((uint32_t) tmpR & 0xff);
233-
data64Ptr[k] = color;
242+
const float scale = 1.0f / float((1 << bitDepth) - 1);
243+
int dstStride = (int) info.width * 4 * (int) sizeof(uint8_t);
244+
auto data64Ptr = reinterpret_cast<uint8_t *>(dstARGB.get());
245+
for (int y = 0; y < info.height; ++y) {
246+
auto srcPtr = reinterpret_cast<uint16_t *>(srcData);
247+
auto dstPtr = reinterpret_cast<uint8_t *>(data64Ptr);
248+
for (int x = 0; x < info.width; ++x) {
249+
auto alpha = half_to_float(srcPtr[3]);
250+
tmpR = (uint8_t) fmin(fmax((half_to_float(srcPtr[0]) / scale), 0), 255);
251+
tmpG = (uint8_t) fmin(fmax((half_to_float(srcPtr[1]) / scale), 0), 255);
252+
tmpB = (uint8_t) fmin(fmax((half_to_float(srcPtr[2]) / scale), 0), 255);
253+
tmpA = (uint8_t) fmin(fmax((alpha / scale), 0), 255);
254+
255+
dstPtr[0] = tmpR;
256+
dstPtr[1] = tmpG;
257+
dstPtr[2] = tmpB;
258+
dstPtr[3] = tmpA;
259+
260+
srcPtr += 4;
261+
dstPtr += 4;
262+
}
263+
264+
srcData += info.stride;
265+
data64Ptr += dstStride;
234266
}
235-
auto *dataPtr = reinterpret_cast<void *>(dstARGB.get());
267+
auto dataPtr = reinterpret_cast<void *>(dstARGB.get());
236268
auto srcY = (char *) dataPtr;
237269
auto dstY = (char *) imgData;
238270
const auto sourceStride = info.width * 4 * sizeof(uint8_t);
@@ -683,8 +715,8 @@ Java_com_radzivon_bartoshyk_avif_coder_HeifCoder_decodeImpl(JNIEnv *env, jobject
683715
heif_image_release(img);
684716
}
685717

686-
std::shared_ptr<char> dstARGB(static_cast<char *>(malloc(stride * imageHeight)),
687-
[](char *f) { free(f); });
718+
std::shared_ptr<uint8_t> dstARGB(static_cast<uint8_t *>(malloc(stride * imageHeight)),
719+
[](uint8_t *f) { free(f); });
688720

689721
if (useBitmapHalf16Floats) {
690722
const float scale = 1.0f / float((1 << bitDepth) - 1);
@@ -752,13 +784,27 @@ Java_com_radzivon_bartoshyk_avif_coder_HeifCoder_decodeImpl(JNIEnv *env, jobject
752784
jobject bitmapObj = env->CallStaticObjectMethod(bitmapClass, createBitmapMethodID,
753785
imageWidth, imageHeight, rgba8888Obj);
754786

787+
AndroidBitmapInfo info;
788+
if (AndroidBitmap_getInfo(env, bitmapObj, &info) < 0) {
789+
throwPixelsException(env);
790+
return static_cast<jbyteArray>(nullptr);
791+
}
792+
755793
void *addr;
756794
if (AndroidBitmap_lockPixels(env, bitmapObj, &addr) != 0) {
757795
throwPixelsException(env);
758796
return static_cast<jobject>(nullptr);
759797
}
760798

761-
std::copy(dstARGB.get(), dstARGB.get() + stride * imageHeight, (char *) addr);
799+
if (useBitmapHalf16Floats) {
800+
copyRGBA16(dstARGB, stride, reinterpret_cast<uint8_t *>(addr), (int) info.stride,
801+
(int) info.width,
802+
(int) info.height);
803+
} else {
804+
libyuv::ARGBCopy(reinterpret_cast<uint8_t *>(dstARGB.get()), stride,
805+
reinterpret_cast<uint8_t *>(addr), (int) info.stride, (int) info.width,
806+
(int) info.height);
807+
}
762808

763809
if (AndroidBitmap_unlockPixels(env, bitmapObj) != 0) {
764810
throwPixelsException(env);

avif-coder/src/main/cpp/colorspace.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ double PQInverseEOTF(double q) {
8181
// }
8282
*/
8383

84-
void convertUseDefinedColorSpace(std::shared_ptr<char> &vector, int stride, int width, int height,
84+
void convertUseDefinedColorSpace(std::shared_ptr<uint8_t> &vector, int stride, int width, int height,
8585
const unsigned char *colorSpace, size_t colorSpaceSize,
8686
bool image16Bits, int *newStride) {
8787
cmsContext context = cmsCreateContext(nullptr, nullptr);

avif-coder/src/main/cpp/colorspace.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include "displayP3_HLG.h"
1616
#include "itur2100_pq_full.h"
1717

18-
void convertUseDefinedColorSpace(std::shared_ptr<char> &vector, int stride, int width, int height,
18+
void convertUseDefinedColorSpace(std::shared_ptr<uint8_t> &vector, int stride, int width, int height,
1919
const unsigned char *colorSpace, size_t colorSpaceSize,
2020
bool image16Bits, int * newStride);
2121

0 commit comments

Comments
 (0)