Skip to content

Commit d6e18cb

Browse files
committed
Done all proper color conversions
1 parent c6e8dd4 commit d6e18cb

File tree

8 files changed

+176
-27
lines changed

8 files changed

+176
-27
lines changed

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,19 @@ class MainActivity : AppCompatActivity() {
3939
val buffer = this.assets.open("hato-wide-gamut.avif").source().buffer().readByteArray()
4040
// assert(HeifCoder().isAvif(buffer))
4141
val size = HeifCoder().getSize(buffer)!!
42-
val bitmap = HeifCoder().decodeSampled(buffer, size.width / 3, size.height / 3)
42+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
43+
val bitmap = HeifCoder().decodeSampled(buffer, size.width / 3, size.height / 3)
44+
.copy(Bitmap.Config.RGBA_1010102, true)
4345
// val opts = BitmapFactory.Options()
4446
// opts.inMutable = true
4547
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
4648
// opts.inPreferredConfig = Bitmap.Config.RGBA_F16
4749
// }
48-
binding.imageView.setImageBitmap(bitmap)
49-
val encoded = HeifCoder().encodeAvif(bitmap)
50-
val decodedSample = HeifCoder().decode(encoded)
51-
binding.imageView.setImageBitmap(decodedSample)
50+
binding.imageView.setImageBitmap(bitmap)
51+
val encoded = HeifCoder().encodeHeic(bitmap)
52+
val decodedSample = HeifCoder().decode(encoded)
53+
binding.imageView.setImageBitmap(decodedSample)
54+
}
5255

5356
// binding.imageView.load("https://wh.aimuse.online/creatives/IMUSE_03617fe2db82a584166_27/TT_a9d21ff1061d785347935fef/68f06252.avif",
5457
// imageLoader = ImageLoader.Builder(this)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ add_library( # Sets the name of the library.
1818
icc/cmsgmt.c icc/cmshalf.c icc/cmsintrp.c icc/cmsio0.c icc/cmsio1.c icc/cmslut.c icc/cmsmd5.c icc/cmsmtrx.c icc/cmsnamed.c
1919
icc/cmsopt.c icc/cmspack.c icc/cmspcs.c icc/cmsplugin.c icc/cmsps2.c icc/cmssamp.c icc/cmssm.c icc/cmstypes.c icc/cmsvirt.c
2020
icc/cmswtpnt.c icc/cmsxform.c rgba_to_bgra_neon.cpp rgba_to_bgra.cpp colorspace.cpp halfFloats.cpp
21-
rgba16bitCopy.cpp rgbaF16bitToNBitU16.cpp rgbaF16bitNBitU8.cpp)
21+
rgba16bitCopy.cpp rgbaF16bitToNBitU16.cpp rgbaF16bitNBitU8.cpp rgb1010102.cpp)
2222

2323
add_library(libaom STATIC IMPORTED)
2424
add_library(libx265 STATIC IMPORTED)

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

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "rgba16bitCopy.h"
2121
#include "rgbaF16bitToNBitU16.h"
2222
#include "rgbaF16bitNBitU8.h"
23+
#include "rgb1010102.h"
2324

2425
struct AvifMemEncoder {
2526
std::vector<char> buffer;
@@ -100,8 +101,10 @@ jbyteArray encodeBitmap(JNIEnv *env, jobject thiz,
100101

101102
heif_image *image;
102103
heif_chroma chroma = heif_chroma_interleaved_RGBA;
103-
if (info.format == ANDROID_BITMAP_FORMAT_RGBA_F16 &&
104-
heifCompressionFormat == heif_compression_AV1) {
104+
if ((info.format == ANDROID_BITMAP_FORMAT_RGBA_F16 &&
105+
heifCompressionFormat == heif_compression_AV1) ||
106+
(info.format == ANDROID_BITMAP_FORMAT_RGBA_1010102 &&
107+
heifCompressionFormat == heif_compression_AV1)) {
105108
chroma = heif_chroma_interleaved_RRGGBBAA_LE;
106109
}
107110
result = heif_image_create((int) info.width, (int) info.height, heif_colorspace_RGB,
@@ -145,23 +148,13 @@ jbyteArray encodeBitmap(JNIEnv *env, jobject thiz,
145148
}
146149
} else if (info.format == ANDROID_BITMAP_FORMAT_RGBA_1010102) {
147150
if (heifCompressionFormat == heif_compression_HEVC) {
148-
auto dstY = (char *) imgData;
149-
auto srcY = (char *) sourceData.data();
150-
for (int y = 0; y < info.height; ++y) {
151-
memcpy(dstY, srcY, info.width * 4 * sizeof(uint32_t));
152-
srcY += info.width * sizeof(uint64_t);
153-
dstY += stride;
154-
}
151+
RGBA1010102ToU8(reinterpret_cast<uint8_t *>(sourceData.data()), (int) info.stride,
152+
reinterpret_cast<uint8_t *>(imgData), stride, (int) info.width,
153+
(int) info.height);
155154
} else {
156-
libyuv::AR30ToARGB(sourceData.data(), (int) info.stride, imgData,
157-
stride, (int) info.width,
158-
(int) info.height);
159-
for (int i = 0; i < stride / 4 * info.height; i += 4) {
160-
imgData[i] = imgData[i + 1]; // R
161-
imgData[i + 1] = imgData[i + 2]; // G
162-
imgData[i + 2] = imgData[i + 3]; // B
163-
imgData[i + 3] = imgData[i]; // A
164-
}
155+
RGBA1010102ToU16(reinterpret_cast<uint8_t *>(sourceData.data()), (int) info.stride,
156+
reinterpret_cast<uint16_t *>(imgData), stride, (int) info.width,
157+
(int) info.height);
165158
}
166159
} else if (info.format == ANDROID_BITMAP_FORMAT_RGBA_F16) {
167160
if (heifCompressionFormat == heif_compression_AV1) {
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//
2+
// Created by Radzivon Bartoshyk on 05/09/2023.
3+
//
4+
5+
#include "rgb1010102.h"
6+
#include <vector>
7+
8+
void convertRGBA1010102ToU16_C(const uint8_t *src, int srcStride, uint16_t *dst, int dstStride,
9+
int width, int height) {
10+
auto mDstPointer = reinterpret_cast<uint8_t *>(dst);
11+
auto mSrcPointer = reinterpret_cast<const uint8_t *>(src);
12+
13+
uint32_t testValue = 0x01020304;
14+
auto testBytes = reinterpret_cast<uint8_t *>(&testValue);
15+
16+
bool littleEndian = false;
17+
if (testBytes[0] == 0x04) {
18+
littleEndian = true;
19+
} else if (testBytes[0] == 0x01) {
20+
littleEndian = false;
21+
}
22+
23+
for (int y = 0; y < height; ++y) {
24+
25+
auto dstPointer = reinterpret_cast<uint8_t *>(mDstPointer);
26+
auto srcPointer = reinterpret_cast<const uint8_t *>(mSrcPointer);
27+
28+
for (int x = 0; x < width; ++x) {
29+
uint32_t rgba1010102 = reinterpret_cast<const uint32_t *>(srcPointer)[0];
30+
31+
const uint32_t mask = (1u << 10u) - 1u;
32+
uint32_t b = (rgba1010102) & mask;
33+
uint32_t g = (rgba1010102 >> 10) & mask;
34+
uint32_t r = (rgba1010102 >> 20) & mask;
35+
36+
uint32_t a1 = (rgba1010102 >> 30);
37+
uint32_t a = (a1 << 8) | (a1 << 6) | (a1 << 4) | (a1 << 2) | a1;
38+
39+
// Convert each channel to floating-point values
40+
auto rFloat = static_cast<uint16_t>(r);
41+
auto gFloat = static_cast<uint16_t>(g);
42+
auto bFloat = static_cast<uint16_t>(b);
43+
auto aFloat = static_cast<uint16_t>(a);
44+
45+
auto dstCast = reinterpret_cast<uint16_t *>(dstPointer);
46+
if (littleEndian) {
47+
dstCast[0] = bFloat;
48+
dstCast[1] = gFloat;
49+
dstCast[2] = rFloat;
50+
dstCast[3] = aFloat;
51+
} else {
52+
dstCast[0] = rFloat;
53+
dstCast[1] = gFloat;
54+
dstCast[2] = bFloat;
55+
dstCast[3] = aFloat;
56+
}
57+
58+
srcPointer += 4;
59+
dstPointer += 8;
60+
}
61+
62+
mSrcPointer += srcStride;
63+
mDstPointer += dstStride;
64+
}
65+
}
66+
67+
void convertRGBA1010102ToU8_C(const uint8_t *src, int srcStride, uint8_t *dst, int dstStride,
68+
int width, int height) {
69+
auto mDstPointer = reinterpret_cast<uint8_t *>(dst);
70+
auto mSrcPointer = reinterpret_cast<const uint8_t *>(src);
71+
72+
uint32_t testValue = 0x01020304;
73+
auto testBytes = reinterpret_cast<uint8_t *>(&testValue);
74+
75+
bool littleEndian = false;
76+
if (testBytes[0] == 0x04) {
77+
littleEndian = true;
78+
} else if (testBytes[0] == 0x01) {
79+
littleEndian = false;
80+
}
81+
82+
for (int y = 0; y < height; ++y) {
83+
84+
auto dstPointer = reinterpret_cast<uint8_t *>(mDstPointer);
85+
auto srcPointer = reinterpret_cast<const uint8_t *>(mSrcPointer);
86+
87+
for (int x = 0; x < width; ++x) {
88+
uint32_t rgba1010102 = reinterpret_cast<const uint32_t *>(srcPointer)[0];
89+
90+
const uint32_t mask = (1u << 10u) - 1u;
91+
uint32_t b = (rgba1010102) & mask;
92+
uint32_t g = (rgba1010102 >> 10) & mask;
93+
uint32_t r = (rgba1010102 >> 20) & mask;
94+
95+
uint32_t a1 = (rgba1010102 >> 30);
96+
uint32_t a = (a1 << 8) | (a1 << 6) | (a1 << 4) | (a1 << 2) | a1;
97+
98+
// Convert each channel to floating-point values
99+
auto rFloat = std::max(std::min(static_cast<uint8_t>((r * 255) / 1023), (uint8_t) 255),
100+
(uint8_t) 0);
101+
auto gFloat = std::max(std::min(static_cast<uint8_t>((g * 255) / 1023), (uint8_t) 255),
102+
(uint8_t) 0);
103+
auto bFloat = std::max(std::min(static_cast<uint8_t>((b * 255) / 1023), (uint8_t) 255),
104+
(uint8_t) 0);
105+
auto aFloat = std::max(std::min(static_cast<uint8_t>((a * 255) / 1023), (uint8_t) 255),
106+
(uint8_t) 0);
107+
108+
auto dstCast = reinterpret_cast<uint8_t *>(dstPointer);
109+
if (littleEndian) {
110+
dstCast[0] = bFloat;
111+
dstCast[1] = gFloat;
112+
dstCast[2] = rFloat;
113+
dstCast[3] = aFloat;
114+
} else {
115+
dstCast[0] = rFloat;
116+
dstCast[1] = gFloat;
117+
dstCast[2] = bFloat;
118+
dstCast[3] = aFloat;
119+
}
120+
121+
srcPointer += 4;
122+
dstPointer += 4;
123+
}
124+
125+
mSrcPointer += srcStride;
126+
mDstPointer += dstStride;
127+
}
128+
}
129+
130+
void RGBA1010102ToU8(const uint8_t *src, int srcStride, uint8_t *dst, int dstStride,
131+
int width, int height) {
132+
convertRGBA1010102ToU8_C(src, srcStride, dst, dstStride, width, height);
133+
}
134+
135+
void RGBA1010102ToU16(const uint8_t *src, int srcStride, uint16_t *dst, int dstStride,
136+
int width, int height) {
137+
convertRGBA1010102ToU16_C(src, srcStride, dst, dstStride, width, height);
138+
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//
2+
// Created by Radzivon Bartoshyk on 05/09/2023.
3+
//
4+
5+
#ifndef AVIF_RGB1010102_H
6+
#define AVIF_RGB1010102_H
7+
8+
#include <vector>
9+
10+
void RGBA1010102ToU16(const uint8_t *src, int srcStride, uint16_t *dst, int dstStride,
11+
int width, int height);
12+
void RGBA1010102ToU8(const uint8_t *src, int srcStride, uint8_t *dst, int dstStride,
13+
int width, int height);
14+
15+
#endif //AVIF_RGB1010102_H

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void copyRGBA16_NEON(uint16_t* source, int srcStride,
2929
dstPtr += 8;
3030
}
3131

32-
for (x = 0; x < width; ++x) {
32+
for (; x < width; ++x) {
3333
auto srcPtr64 = reinterpret_cast<uint64_t *>(srcPtr);
3434
auto dstPtr64 = reinterpret_cast<uint64_t *>(dstPtr);
3535
dstPtr64[0] = srcPtr64[0];

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void RGBAF16BitToNU8_NEON(const uint16_t *sourceData, int srcStride,
4848
srcPtr += 8;
4949
}
5050

51-
for (x = 0; x < width; ++x) {
51+
for (; x < width; ++x) {
5252
auto alpha = half_to_float(srcPtr[3]);
5353
auto tmpR = (uint16_t) std::min(std::max((half_to_float(srcPtr[0]) / scale), 0.0f), maxColors);
5454
auto tmpG = (uint16_t) fmin(std::max((half_to_float(srcPtr[1]) / scale), 0.0f), maxColors);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ void RGBAF16BitToNU16_NEON(const uint16_t *sourceData, int srcStride, uint16_t *
4646
dstPtr += 8;
4747
}
4848

49-
for (x = 0; x < width; ++x) {
49+
for (; x < width; ++x) {
5050
auto alpha = half_to_float(srcPtr[3]);
5151
auto tmpR = (uint16_t) std::min(std::max((half_to_float(srcPtr[0]) / scale), 0.0f),
5252
maxColors);

0 commit comments

Comments
 (0)