KVFCodec
This commit is contained in:
@@ -0,0 +1,471 @@
|
||||
|
||||
/**
|
||||
* Zigzag 映射:将有符号字节映射为非负字节
|
||||
* 0→0, -1→1, 1→2, -2→3, 2→4, ...
|
||||
*/
|
||||
uchar zigzag_map(char x) {
|
||||
int v = (int)x; // char 转为 int(保留符号)
|
||||
return (uchar)((v >= 0) ? (v << 1) : ((-v << 1) - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Zigzag 逆映射:将非负字节还原为有符号字节
|
||||
* 0→0, 1→-1, 2→1, 3→-2, 4→2, ...
|
||||
*/
|
||||
char zigzag_unmap(uchar y) {
|
||||
int v = (int)y; // 转为无符号 0~255
|
||||
return (char)((v & 1) == 0 ? (v >> 1) : (-((v + 1) >> 1)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 像素安全加法:RGBA 四个通道分别相加,结果裁剪到 0~255
|
||||
*/
|
||||
int pixelAdd(int a, int b) {
|
||||
int ar = (a >> 16) & 0xFF;
|
||||
int ag = (a >> 8) & 0xFF;
|
||||
int ab = a & 0xFF;
|
||||
int aa = (a >> 24) & 0xFF;
|
||||
|
||||
int br = (b >> 16) & 0xFF;
|
||||
int bg = (b >> 8) & 0xFF;
|
||||
int bb = b & 0xFF;
|
||||
int ba = (b >> 24) & 0xFF;
|
||||
|
||||
int r = ar + br;
|
||||
int g = ag + bg;
|
||||
int bv = ab + bb;
|
||||
int av = aa + ba;
|
||||
|
||||
// 用 &0xFF 替代 min/max,保留低 8 位(自动溢出,等同于裁剪)
|
||||
return ((av & 0xFF) << 24) |
|
||||
((r & 0xFF) << 16) |
|
||||
((g & 0xFF) << 8) |
|
||||
(bv & 0xFF);
|
||||
}
|
||||
/**
|
||||
* 像素安全减法(等效于 Java 的 pixelSub)
|
||||
* 逐通道相减,结果裁剪到 0~255,组装回 ARGB
|
||||
*/
|
||||
int pixelSub(int a, int b) {
|
||||
int ar = (a >> 16) & 0xFF;
|
||||
int ag = (a >> 8) & 0xFF;
|
||||
int ab = a & 0xFF;
|
||||
int aa = (a >> 24) & 0xFF;
|
||||
|
||||
int br = (b >> 16) & 0xFF;
|
||||
int bg = (b >> 8) & 0xFF;
|
||||
int bb = b & 0xFF;
|
||||
int ba = (b >> 24) & 0xFF;
|
||||
|
||||
int r = ar - br;
|
||||
int g = ag - bg;
|
||||
int bv = ab - bb;
|
||||
int av = aa - ba;
|
||||
|
||||
return ((av & 0xFF) << 24) |
|
||||
((r & 0xFF) << 16) |
|
||||
((g & 0xFF) << 8) |
|
||||
(bv & 0xFF);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 位平面编码(矩阵转置风格)- 等效于 Java 版本
|
||||
*
|
||||
* 核心逻辑:
|
||||
* 对于输出数组的每个字节,依次从输入数组的8个位平面各取1个bit
|
||||
* 即:输出字节的 bit i = 输入数组第 i 个位平面的当前位
|
||||
*
|
||||
* 输出数组的每个字节,由8个位平面的各1个bit组成
|
||||
* 等价于:把 8×len 的 bit 矩阵转置为 len×8 的 bit 矩阵
|
||||
*/
|
||||
__kernel void encodePacked(
|
||||
__global const uchar* input, // 输入字节数组
|
||||
__global uchar* output, // 输出字节数组(长度与输入相同)
|
||||
int len // 输入/输出长度
|
||||
) {
|
||||
int outIdx = get_global_id(0);
|
||||
if (outIdx >= len) return;
|
||||
|
||||
int outByte = 0;
|
||||
|
||||
// 从8个位平面各取1个bit,组装成一个字节
|
||||
for (int plane = 0; plane < 8; plane++) {
|
||||
int bitpos = (outIdx << 3) + plane;
|
||||
int inputPos = bitpos % len;
|
||||
int bitShift = bitpos / len;
|
||||
int bit = (input[inputPos] >> (7 - bitShift)) & 1;
|
||||
outByte |= (bit << plane);
|
||||
}
|
||||
|
||||
output[outIdx] = (uchar)outByte;
|
||||
}
|
||||
|
||||
__kernel void decodePacked(__global const unsigned char* datain,
|
||||
__global unsigned char* dataout,
|
||||
int size) {
|
||||
int outIdx = get_global_id(0);
|
||||
|
||||
// 边界检查
|
||||
if (outIdx >= size) {
|
||||
return;
|
||||
}
|
||||
|
||||
int outByte = 0;
|
||||
|
||||
// 从 8 个位平面各取 1 个 bit,组装成一个字节
|
||||
// plane 0 → bit7, plane 1 → bit6, ..., plane 7 → bit0
|
||||
for (int plane = 0; plane < 8; plane++) {
|
||||
int bitpos = plane * size + outIdx;
|
||||
int inputpos = bitpos >> 3;
|
||||
int inputshift = bitpos & 0b111;
|
||||
int bit = (datain[inputpos] >> inputshift) & 1;
|
||||
outByte |= (bit << (7 - plane));
|
||||
}
|
||||
|
||||
dataout[outIdx] = (unsigned char)outByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化 + Zigzag 映射(RGBA 交错)
|
||||
*/
|
||||
__kernel void serializeRGBAWithZigzag(
|
||||
__global int* pixels,
|
||||
__global uchar* output,
|
||||
int size
|
||||
) {
|
||||
int i = get_global_id(0);
|
||||
if (i >= size) return;
|
||||
|
||||
int pixel = pixels[i];
|
||||
|
||||
char r = (char)((pixel >> 16) & 0xFF);
|
||||
char g = (char)((pixel >> 8) & 0xFF);
|
||||
char b = (char)(pixel & 0xFF);
|
||||
char a = (char)((pixel >> 24) & 0xFF);
|
||||
|
||||
int idx = i * 4;
|
||||
output[idx + 0] = zigzag_map(r);
|
||||
output[idx + 1] = zigzag_map(g);
|
||||
output[idx + 2] = zigzag_map(b);
|
||||
output[idx + 3] = zigzag_map(a);
|
||||
}
|
||||
// 对应 deserializeRGBAWithZigzag
|
||||
__kernel void deserializeRGBAWithZigzag(
|
||||
__global const uchar* data, // 输入:Zigzag 映射后的字节流(RGBA 交错)
|
||||
__global int* pixels, // 输出:像素数组(ARGB)
|
||||
int size // 像素数量 (w * h)
|
||||
) {
|
||||
int i = get_global_id(0);
|
||||
if (i >= size) return;
|
||||
|
||||
int idx = i * 4;
|
||||
|
||||
// 读取并逆映射四个通道
|
||||
uchar r_raw = data[idx];
|
||||
uchar g_raw = data[idx + 1];
|
||||
uchar b_raw = data[idx + 2];
|
||||
uchar a_raw = data[idx + 3];
|
||||
|
||||
char r = zigzag_unmap(r_raw);
|
||||
char g = zigzag_unmap(g_raw);
|
||||
char b = zigzag_unmap(b_raw);
|
||||
char a = zigzag_unmap(a_raw);
|
||||
|
||||
// 组装成 ARGB (Java 的 int 格式)
|
||||
// 注意:OpenCL 的 int 是 32 位有符号,和 Java 一致
|
||||
pixels[i] = ((int)(a & 0xFF) << 24) |
|
||||
((int)(r & 0xFF) << 16) |
|
||||
((int)(g & 0xFF) << 8) |
|
||||
(int)(b & 0xFF);
|
||||
}
|
||||
/**
|
||||
* 序列化 + Zigzag 映射(平面 RGBA)
|
||||
*/
|
||||
__kernel void serializePlannarRGBAWithZigzag(
|
||||
__global int* pixels,
|
||||
__global uchar* output,
|
||||
int size
|
||||
) {
|
||||
int i = get_global_id(0);
|
||||
if (i >= size) return;
|
||||
|
||||
int pixel = pixels[i];
|
||||
|
||||
char r = (char)((pixel >> 16) & 0xFF);
|
||||
char g = (char)((pixel >> 8) & 0xFF);
|
||||
char b = (char)(pixel & 0xFF);
|
||||
char a = (char)((pixel >> 24) & 0xFF);
|
||||
|
||||
int rOffset = 0;
|
||||
int gOffset = size;
|
||||
int bOffset = size * 2;
|
||||
int aOffset = size * 3;
|
||||
|
||||
output[rOffset + i] = zigzag_map(r);
|
||||
output[gOffset + i] = zigzag_map(g);
|
||||
output[bOffset + i] = zigzag_map(b);
|
||||
output[aOffset + i] = zigzag_map(a);
|
||||
}
|
||||
// 对应 deserializePlannarRGBAWithZigzag
|
||||
__kernel void deserializePlannarRGBAWithZigzag(
|
||||
__global const uchar* data, // 输入:Zigzag 映射后的字节流(RRRR...GGGG...BBBB...AAAA...)
|
||||
__global int* pixels, // 输出:像素数组(ARGB)
|
||||
int size // 像素数量 (w * h)
|
||||
) {
|
||||
int i = get_global_id(0);
|
||||
if (i >= size) return;
|
||||
|
||||
int rOffset = 0;
|
||||
int gOffset = size;
|
||||
int bOffset = size * 2;
|
||||
int aOffset = size * 3;
|
||||
|
||||
// 从四个平面分别读取并逆映射
|
||||
uchar r_raw = data[rOffset + i];
|
||||
uchar g_raw = data[gOffset + i];
|
||||
uchar b_raw = data[bOffset + i];
|
||||
uchar a_raw = data[aOffset + i];
|
||||
|
||||
char r = zigzag_unmap(r_raw);
|
||||
char g = zigzag_unmap(g_raw);
|
||||
char b = zigzag_unmap(b_raw);
|
||||
char a = zigzag_unmap(a_raw);
|
||||
|
||||
// 组装成 ARGB
|
||||
pixels[i] = ((int)(a & 0xFF) << 24) |
|
||||
((int)(r & 0xFF) << 16) |
|
||||
((int)(g & 0xFF) << 8) |
|
||||
(int)(b & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* 水平预测(非原地,完美并行)
|
||||
* residual = pixelSub(current, left)
|
||||
* 每个线程独立处理一个像素
|
||||
*/
|
||||
__kernel void horizontalPredictParallel(
|
||||
__global const int* input, // 原始像素
|
||||
__global int* output, // 残差输出
|
||||
int w,
|
||||
int h
|
||||
) {
|
||||
int idx = get_global_id(0);
|
||||
int size = w * h;
|
||||
if (idx >= size) return;
|
||||
|
||||
int x = idx % w;
|
||||
|
||||
if (x == 0) {
|
||||
// 第一列:残差 = 原值(没有左邻居)
|
||||
output[idx] = input[idx];
|
||||
} else {
|
||||
int left = input[idx - 1];
|
||||
output[idx] = pixelSub(input[idx], left);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 垂直预测(非原地,完美并行)
|
||||
* residual = pixelSub(current, above)
|
||||
* 每个线程独立处理一个像素
|
||||
*/
|
||||
__kernel void verticalPredictParallel(
|
||||
__global const int* input, // 原始像素(或水平预测后的残差)
|
||||
__global int* output, // 残差输出
|
||||
int w,
|
||||
int h
|
||||
) {
|
||||
int idx = get_global_id(0);
|
||||
int size = w * h;
|
||||
if (idx >= size) return;
|
||||
|
||||
int y = idx / w;
|
||||
|
||||
if (y == 0) {
|
||||
// 第一行:残差 = 原值(没有上邻居)
|
||||
output[idx] = input[idx];
|
||||
} else {
|
||||
int above = input[idx - w];
|
||||
output[idx] = pixelSub(input[idx], above);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 水平预测(使用 pixelSub)
|
||||
* residual = pixelSub(current, left)
|
||||
* 从右向左,保证 left 是原始值
|
||||
*/
|
||||
__kernel void horizontalPredictInPlace(
|
||||
__global int* data,
|
||||
int w,
|
||||
int h
|
||||
) {
|
||||
int row = get_global_id(0);
|
||||
if (row >= h) return;
|
||||
|
||||
int base = row * w;
|
||||
|
||||
// 从右向左(第一列不变)
|
||||
for (int x = w - 1; x >= 1; x--) {
|
||||
int idx = base + x;
|
||||
int left = data[idx - 1];
|
||||
data[idx] = pixelSub(data[idx], left);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 水平逆预测(原地操作)
|
||||
* 每个工作组处理一行,行内从左到右串行
|
||||
*
|
||||
* 数据依赖:左侧像素 (x-1, y) 必须先被还原
|
||||
*//**
|
||||
* 水平逆预测(寄存器优化版)
|
||||
*
|
||||
* 核心优化:预测值在寄存器中传递,减少显存读取
|
||||
*/
|
||||
__kernel void horizontalInverseInPlace(
|
||||
__global int* data,
|
||||
int w,
|
||||
int h
|
||||
) {
|
||||
int row = get_global_id(0);
|
||||
if (row >= h) return;
|
||||
|
||||
int base = row * w;
|
||||
|
||||
// 第一列保持不变
|
||||
// 直接用 data[base] 作为初始预测值
|
||||
int pred = data[base]; // ✅ 只读一次显存
|
||||
|
||||
// 行内从左到右串行,但 pred 在寄存器中传递
|
||||
for (int x = 1; x < w; x++) {
|
||||
int idx = base + x;
|
||||
int residual = data[idx]; // ✅ 只读残差
|
||||
int result = pixelAdd(pred, residual);
|
||||
data[idx] = result; // ✅ 只写一次显存
|
||||
pred = result; // ✅ 寄存器传递(下次循环直接使用)
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 垂直预测(使用 pixelSub)
|
||||
* residual = pixelSub(current, above)
|
||||
* 从下向上,保证 above 是原始值
|
||||
*/
|
||||
__kernel void verticalPredictInPlace(
|
||||
__global int* data,
|
||||
int w,
|
||||
int h
|
||||
) {
|
||||
int col = get_global_id(0);
|
||||
if (col >= w) return;
|
||||
|
||||
// 从下向上(第一行不变)
|
||||
for (int y = h - 1; y >= 1; y--) {
|
||||
int idx = y * w + col;
|
||||
int above = data[(y - 1) * w + col];
|
||||
data[idx] = pixelSub(data[idx], above);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 垂直逆预测(原地操作)
|
||||
* 每个工作组处理一列,列内从上到下串行
|
||||
*
|
||||
* 数据依赖:上方像素 (x, y-1) 必须先被还原
|
||||
*//**
|
||||
* 垂直逆预测(寄存器优化版)
|
||||
*/
|
||||
__kernel void verticalInverseInPlace(
|
||||
__global int* data,
|
||||
int w,
|
||||
int h
|
||||
) {
|
||||
int col = get_global_id(0);
|
||||
if (col >= w) return;
|
||||
|
||||
// 第一行:用 data[col] 作为初始预测值
|
||||
int pred = data[col]; // ✅ 只读一次显存
|
||||
|
||||
for (int y = 1; y < h; y++) {
|
||||
int idx = y * w + col;
|
||||
int residual = data[idx]; // ✅ 只读残差
|
||||
int result = pixelAdd(pred, residual);
|
||||
data[idx] = result;
|
||||
pred = result; // ✅ 寄存器传递
|
||||
}
|
||||
}
|
||||
/**
|
||||
* RGBA 颜色变换(原地版本)- 等效于 Java 的 colorTransformRGBAInPlace
|
||||
*
|
||||
* 编码:R' = R - G, G' = G, B' = B - G, A' = A
|
||||
* 结果存储为:A | R' | G | B'(与 Java 版本完全一致)
|
||||
*/
|
||||
__kernel void colorTransformRGBAInPlace(
|
||||
__global int* data, // 输入/输出像素数组
|
||||
int size // 像素总数 (w * h)
|
||||
) {
|
||||
int idx = get_global_id(0);
|
||||
if (idx >= size) return;
|
||||
|
||||
int pixel = data[idx];
|
||||
|
||||
int r = (pixel >> 16) & 0xFF;
|
||||
int g = (pixel >> 8) & 0xFF;
|
||||
int b = pixel & 0xFF;
|
||||
int a = (pixel >> 24) & 0xFF;
|
||||
|
||||
int rg = r - g; // 范围 -255 ~ 255
|
||||
int bg = b - g; // 范围 -255 ~ 255
|
||||
|
||||
// 与 Java 版本完全一致:
|
||||
// ((a & 0xFF) << 24) | ((rg & 0xFF) << 16) | ((g & 0xFF) << 8) | (bg & 0xFF)
|
||||
data[idx] = ((a & 0xFF) << 24) |
|
||||
((rg & 0xFF) << 16) |
|
||||
((g & 0xFF) << 8) |
|
||||
(bg & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* 颜色逆变换(RGBA,逐像素并行)- 与 colorTransformRGBAInPlace 完全对应
|
||||
*
|
||||
* Java 版本:
|
||||
* a = (packed >> 24) & 0xFF
|
||||
* rg = (packed >> 16) & 0xFF
|
||||
* g = (packed >> 8) & 0xFF
|
||||
* bg = packed & 0xFF
|
||||
* r = g + rg
|
||||
* b = g + bg
|
||||
* result = (a << 24) | (r << 16) | (g << 8) | b
|
||||
*/
|
||||
__kernel void colorInverseRGBAInPlace(
|
||||
__global int* data, // 输入:颜色差分数据,输出:还原后的 RGBA
|
||||
int size // 像素总数 (w * h)
|
||||
) {
|
||||
int idx = get_global_id(0);
|
||||
if (idx >= size) return;
|
||||
|
||||
int packed = data[idx];
|
||||
|
||||
// 提取各通道
|
||||
int a = (packed >> 24) & 0xFF;
|
||||
int rg = (packed >> 16) & 0xFF;
|
||||
int g = (packed >> 8) & 0xFF;
|
||||
int bg = packed & 0xFF;
|
||||
|
||||
// 还原 R 和 B
|
||||
int r = g + rg;
|
||||
int b = g + bg;
|
||||
|
||||
// 裁剪到 0~255(用 &0xFF 保留低 8 位)
|
||||
r = r & 0xFF;
|
||||
b = b & 0xFF;
|
||||
|
||||
// 组装回 ARGB
|
||||
data[idx] = ((a & 0xFF) << 24) |
|
||||
((r & 0xFF) << 16) |
|
||||
((g & 0xFF) << 8) |
|
||||
(b & 0xFF);
|
||||
}
|
||||
Reference in New Issue
Block a user