@gyeonghokim/fisheye.js 0.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -14
- package/dist/index.d.ts +269 -266
- package/dist/index.js +179 -344
- package/dist/index.js.map +1 -1
- package/package.json +15 -7
package/dist/index.js
CHANGED
|
@@ -1,122 +1,92 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import * as
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
inputTexture: { texture:
|
|
20
|
-
outputTexture: { storageTexture:
|
|
21
|
-
uniforms: { uniform:
|
|
22
|
-
});
|
|
23
|
-
|
|
1
|
+
import M from "typegpu";
|
|
2
|
+
import * as i from "typegpu/data";
|
|
3
|
+
import * as b from "typegpu/std";
|
|
4
|
+
const D = (globalThis.__TYPEGPU_AUTONAME__ ?? ((s) => s))(i.struct({
|
|
5
|
+
k1: i.f32,
|
|
6
|
+
k2: i.f32,
|
|
7
|
+
k3: i.f32,
|
|
8
|
+
k4: i.f32,
|
|
9
|
+
fov: i.f32,
|
|
10
|
+
centerX: i.f32,
|
|
11
|
+
centerY: i.f32,
|
|
12
|
+
zoom: i.f32,
|
|
13
|
+
width: i.f32,
|
|
14
|
+
height: i.f32,
|
|
15
|
+
inputWidth: i.f32,
|
|
16
|
+
inputHeight: i.f32,
|
|
17
|
+
padding: i.f32
|
|
18
|
+
}), "FisheyeUniforms"), P = (globalThis.__TYPEGPU_AUTONAME__ ?? ((s) => s))(M.bindGroupLayout({
|
|
19
|
+
inputTexture: { texture: i.texture2d() },
|
|
20
|
+
outputTexture: { storageTexture: i.textureStorage2d("rgba8unorm") },
|
|
21
|
+
uniforms: { uniform: D }
|
|
22
|
+
}), "fisheyeLayout");
|
|
23
|
+
class X {
|
|
24
24
|
config;
|
|
25
25
|
root = null;
|
|
26
26
|
uniformBuffer = null;
|
|
27
27
|
inputTexture = null;
|
|
28
28
|
outputTexture = null;
|
|
29
|
-
inputView = null;
|
|
30
|
-
outputView = null;
|
|
31
29
|
bindGroup = null;
|
|
32
30
|
dewarpPipeline = null;
|
|
33
31
|
readbackBuffers = null;
|
|
34
32
|
readbackIndex = 0;
|
|
35
|
-
readbackHasData = [
|
|
33
|
+
readbackHasData = [!1, !1];
|
|
36
34
|
readbackBytesPerRow = 0;
|
|
37
35
|
readbackActualBytesPerRow = 0;
|
|
38
36
|
pixelBuffer = null;
|
|
39
37
|
inputTextureSize = [0, 0];
|
|
40
38
|
outputTextureSize = [0, 0];
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return texture.createView(d.textureStorage2d("rgba8unorm"));
|
|
46
|
-
}
|
|
47
|
-
constructor(options = {}) {
|
|
48
|
-
this.config = this.applyDefaults(options);
|
|
39
|
+
uniformInputWidth = 0;
|
|
40
|
+
uniformInputHeight = 0;
|
|
41
|
+
constructor(t = {}) {
|
|
42
|
+
this.config = this.applyDefaults(t);
|
|
49
43
|
}
|
|
50
44
|
/**
|
|
51
45
|
* Apply default values to options
|
|
52
46
|
*/
|
|
53
|
-
applyDefaults(
|
|
54
|
-
const k1 = options.k1 ?? 0;
|
|
47
|
+
applyDefaults(t) {
|
|
55
48
|
return {
|
|
56
|
-
k1,
|
|
57
|
-
k2:
|
|
58
|
-
k3:
|
|
59
|
-
k4:
|
|
60
|
-
width:
|
|
61
|
-
height:
|
|
62
|
-
fov:
|
|
63
|
-
centerX:
|
|
64
|
-
centerY:
|
|
65
|
-
zoom:
|
|
49
|
+
k1: t.k1 ?? 0,
|
|
50
|
+
k2: t.k2 ?? 0,
|
|
51
|
+
k3: t.k3 ?? 0,
|
|
52
|
+
k4: t.k4 ?? 0,
|
|
53
|
+
width: t.width ?? 300,
|
|
54
|
+
height: t.height ?? 150,
|
|
55
|
+
fov: t.fov ?? 180,
|
|
56
|
+
centerX: t.centerX ?? 0,
|
|
57
|
+
centerY: t.centerY ?? 0,
|
|
58
|
+
zoom: t.zoom ?? 1
|
|
66
59
|
};
|
|
67
60
|
}
|
|
68
61
|
/**
|
|
69
62
|
* Initialize TypeGPU root and resources
|
|
70
63
|
*/
|
|
71
64
|
async initialize() {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
this.root = await tgpu.init();
|
|
76
|
-
this.uniformBuffer = this.root.createBuffer(FisheyeUniforms, this.getUniformData()).$usage("uniform");
|
|
77
|
-
this.dewarpPipeline = this.root["~unstable"].createGuardedComputePipeline(
|
|
78
|
-
(x, y) => {
|
|
65
|
+
this.root || (this.root = await M.init(), this.uniformBuffer = (globalThis.__TYPEGPU_AUTONAME__ ?? ((t) => t))(this.root.createBuffer(D, this.getUniformData()).$usage("uniform"), "uniformBuffer"), this.dewarpPipeline = (globalThis.__TYPEGPU_AUTONAME__ ?? ((t) => t))(this.root["~unstable"].createGuardedComputePipeline(
|
|
66
|
+
((t) => (globalThis.__TYPEGPU_META__ ??= /* @__PURE__ */ new WeakMap()).set(t.f = ((o, r) => {
|
|
79
67
|
"use gpu";
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
const params = fisheyeLayout.$.uniforms;
|
|
83
|
-
const inputDims = std.textureDimensions(inputTex);
|
|
84
|
-
const outputDims = std.textureDimensions(outputTex);
|
|
85
|
-
const coord = d.vec2i(x, y);
|
|
86
|
-
if (x >= outputDims.x || y >= outputDims.y) {
|
|
68
|
+
const e = P.$.uniforms, n = e.width, c = e.height, a = e.inputWidth, p = e.inputHeight, l = i.vec2i(o, r);
|
|
69
|
+
if (i.f32(o) >= n || i.f32(r) >= c)
|
|
87
70
|
return;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
(
|
|
91
|
-
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const finalUv = distortedUv.add(d.vec2f(params.centerX, params.centerY)).mul(0.5).add(0.5);
|
|
108
|
-
if (finalUv.x >= 0 && finalUv.x <= 1 && finalUv.y >= 0 && finalUv.y <= 1) {
|
|
109
|
-
const sampleCoord = d.vec2i(
|
|
110
|
-
d.i32(finalUv.x * d.f32(inputDims.x)),
|
|
111
|
-
d.i32(finalUv.y * d.f32(inputDims.y))
|
|
112
|
-
);
|
|
113
|
-
const color = std.textureLoad(inputTex, sampleCoord, 0);
|
|
114
|
-
std.textureStore(outputTex, coord, color);
|
|
115
|
-
} else {
|
|
116
|
-
std.textureStore(outputTex, coord, d.vec4f(0, 0, 0, 1));
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
);
|
|
71
|
+
const x = i.vec2f(
|
|
72
|
+
(i.f32(l.x) / n - 0.5) * 2,
|
|
73
|
+
(i.f32(l.y) / c - 0.5) * 2
|
|
74
|
+
), m = e.centerX, g = e.centerY, u = x.sub(i.vec2f(m, g)), f = b.length(u), k = Math.SQRT2, U = b.min(e.fov * 0.017453293, 3.1), A = b.tan(U * 0.5) / k, H = b.min(A, 1), G = f * H, d = b.atan(G), h = d * d, y = h * h, T = y * h, R = y * y, B = d * (1 + e.k1 * h + e.k2 * y + e.k3 * T + e.k4 * R) / e.zoom;
|
|
75
|
+
let v = i.vec2f(u.x, u.y);
|
|
76
|
+
f > 1e-4 && (v = i.vec2f(u.x * (B / f), u.y * (B / f)));
|
|
77
|
+
const w = v.add(i.vec2f(m, g)).mul(0.5).add(0.5);
|
|
78
|
+
if (w.x >= 0 && w.x <= 1 && w.y >= 0 && w.y <= 1) {
|
|
79
|
+
const I = i.vec2i(i.i32(w.x * a), i.i32(w.y * p)), z = b.textureLoad(P.$.inputTexture, I, 0);
|
|
80
|
+
b.textureStore(P.$.outputTexture, l, z);
|
|
81
|
+
} else
|
|
82
|
+
b.textureStore(P.$.outputTexture, l, i.vec4f(0, 0, 0, 1));
|
|
83
|
+
}), {
|
|
84
|
+
v: 1,
|
|
85
|
+
name: void 0,
|
|
86
|
+
ast: { params: [{ type: "i", name: "x" }, { type: "i", name: "y" }], body: [0, [[13, "p", [7, [7, "fisheyeLayout", "$"], "uniforms"]], [13, "outputW", [7, "p", "width"]], [13, "outputH", [7, "p", "height"]], [13, "inputW", [7, "p", "inputWidth"]], [13, "inputH", [7, "p", "inputHeight"]], [13, "coord", [6, [7, "d", "vec2i"], ["x", "y"]]], [11, [3, [1, [6, [7, "d", "f32"], ["x"]], ">=", "outputW"], "||", [1, [6, [7, "d", "f32"], ["y"]], ">=", "outputH"]], [0, [[10]]]], [13, "uv", [6, [7, "d", "vec2f"], [[1, [1, [1, [6, [7, "d", "f32"], [[7, "coord", "x"]]], "/", "outputW"], "-", [5, "0.5"]], "*", [5, "2"]], [1, [1, [1, [6, [7, "d", "f32"], [[7, "coord", "y"]]], "/", "outputH"], "-", [5, "0.5"]], "*", [5, "2"]]]]], [13, "centerX", [7, "p", "centerX"]], [13, "centerY", [7, "p", "centerY"]], [13, "centered", [6, [7, "uv", "sub"], [[6, [7, "d", "vec2f"], ["centerX", "centerY"]]]]], [13, "r", [6, [7, "std", "length"], ["centered"]]], [13, "cornerNorm", [7, "Math", "SQRT2"]], [13, "fovRad", [6, [7, "std", "min"], [[1, [7, "p", "fov"], "*", [5, "0.017453293"]], [5, "3.1"]]]], [13, "scaleRaw", [1, [6, [7, "std", "tan"], [[1, "fovRad", "*", [5, "0.5"]]]], "/", "cornerNorm"]], [13, "scale", [6, [7, "std", "min"], ["scaleRaw", [5, "1"]]]], [13, "rScaledForFov", [1, "r", "*", "scale"]], [13, "theta", [6, [7, "std", "atan"], ["rScaledForFov"]]], [13, "theta2", [1, "theta", "*", "theta"]], [13, "theta4", [1, "theta2", "*", "theta2"]], [13, "theta6", [1, "theta4", "*", "theta2"]], [13, "theta8", [1, "theta4", "*", "theta4"]], [13, "thetaDistorted", [1, "theta", "*", [1, [1, [1, [1, [5, "1"], "+", [1, [7, "p", "k1"], "*", "theta2"]], "+", [1, [7, "p", "k2"], "*", "theta4"]], "+", [1, [7, "p", "k3"], "*", "theta6"]], "+", [1, [7, "p", "k4"], "*", "theta8"]]]], [13, "rDistorted", "thetaDistorted"], [13, "rScaled", [1, "rDistorted", "/", [7, "p", "zoom"]]], [12, "distortedUv", [6, [7, "d", "vec2f"], [[7, "centered", "x"], [7, "centered", "y"]]]], [11, [1, "r", ">", [5, "0.0001"]], [0, [[2, "distortedUv", "=", [6, [7, "d", "vec2f"], [[1, [7, "centered", "x"], "*", [1, "rScaled", "/", "r"]], [1, [7, "centered", "y"], "*", [1, "rScaled", "/", "r"]]]]]]]], [13, "finalUv", [6, [7, [6, [7, [6, [7, "distortedUv", "add"], [[6, [7, "d", "vec2f"], ["centerX", "centerY"]]]], "mul"], [[5, "0.5"]]], "add"], [[5, "0.5"]]]], [11, [3, [3, [3, [1, [7, "finalUv", "x"], ">=", [5, "0"]], "&&", [1, [7, "finalUv", "x"], "<=", [5, "1"]]], "&&", [1, [7, "finalUv", "y"], ">=", [5, "0"]]], "&&", [1, [7, "finalUv", "y"], "<=", [5, "1"]]], [0, [[13, "sampleCoord", [6, [7, "d", "vec2i"], [[6, [7, "d", "i32"], [[1, [7, "finalUv", "x"], "*", "inputW"]]], [6, [7, "d", "i32"], [[1, [7, "finalUv", "y"], "*", "inputH"]]]]]], [13, "color", [6, [7, "std", "textureLoad"], [[7, [7, "fisheyeLayout", "$"], "inputTexture"], "sampleCoord", [5, "0"]]]], [6, [7, "std", "textureStore"], [[7, [7, "fisheyeLayout", "$"], "outputTexture"], "coord", "color"]]]], [0, [[6, [7, "std", "textureStore"], [[7, [7, "fisheyeLayout", "$"], "outputTexture"], "coord", [6, [7, "d", "vec4f"], [[5, "0"], [5, "0"], [5, "0"], [5, "1"]]]]]]]]]], externalNames: ["fisheyeLayout", "d", "std", "Math"] },
|
|
87
|
+
externals: () => ({ fisheyeLayout: P, d: i, std: b, Math })
|
|
88
|
+
}) && t.f)({})
|
|
89
|
+
), "dewarpPipeline"));
|
|
120
90
|
}
|
|
121
91
|
/**
|
|
122
92
|
* Get uniform data from current configuration
|
|
@@ -133,6 +103,8 @@ var Fisheye = class _Fisheye {
|
|
|
133
103
|
zoom: this.config.zoom,
|
|
134
104
|
width: this.config.width,
|
|
135
105
|
height: this.config.height,
|
|
106
|
+
inputWidth: this.uniformInputWidth,
|
|
107
|
+
inputHeight: this.uniformInputHeight,
|
|
136
108
|
padding: 0
|
|
137
109
|
};
|
|
138
110
|
}
|
|
@@ -140,86 +112,66 @@ var Fisheye = class _Fisheye {
|
|
|
140
112
|
* Update uniform buffer with current configuration
|
|
141
113
|
*/
|
|
142
114
|
updateUniforms() {
|
|
143
|
-
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
this.uniformBuffer.write(this.getUniformData());
|
|
115
|
+
this.uniformBuffer && this.uniformBuffer.write(this.getUniformData());
|
|
147
116
|
}
|
|
148
|
-
async readbackToVideoFrame(
|
|
149
|
-
const
|
|
150
|
-
if (!
|
|
117
|
+
async readbackToVideoFrame(t, o, r) {
|
|
118
|
+
const e = this.readbackBuffers;
|
|
119
|
+
if (!e)
|
|
151
120
|
throw new Error("Readback buffer not initialized");
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const commandEncoder = device.createCommandEncoder();
|
|
155
|
-
const writeIndex = this.readbackIndex;
|
|
156
|
-
const readIndex = 1 - writeIndex;
|
|
157
|
-
const writeBuffer = readbackBuffers[writeIndex];
|
|
158
|
-
const readBuffer = readbackBuffers[readIndex];
|
|
159
|
-
if (!writeBuffer || !readBuffer) {
|
|
121
|
+
const n = this.readbackIndex, c = 1 - n, a = e[n], p = e[c];
|
|
122
|
+
if (!a || !p)
|
|
160
123
|
throw new Error("Readback buffer not initialized");
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
{ texture:
|
|
164
|
-
{ buffer:
|
|
124
|
+
const l = t.createCommandEncoder();
|
|
125
|
+
l.copyTextureToBuffer(
|
|
126
|
+
{ texture: o },
|
|
127
|
+
{ buffer: a, bytesPerRow: this.readbackBytesPerRow },
|
|
165
128
|
[this.config.width, this.config.height]
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
this.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
for (let row = 0; row < this.config.height; row++) {
|
|
176
|
-
const srcOffset = row * this.readbackBytesPerRow;
|
|
177
|
-
const dstOffset = row * this.readbackActualBytesPerRow;
|
|
178
|
-
pixelData.set(
|
|
179
|
-
srcView.subarray(srcOffset, srcOffset + this.readbackActualBytesPerRow),
|
|
180
|
-
dstOffset
|
|
129
|
+
), t.queue.submit([l.finish()]), await t.queue.onSubmittedWorkDone(), this.readbackHasData[n] = !0, this.readbackIndex = c;
|
|
130
|
+
const x = this.readbackHasData[c] ? p : a;
|
|
131
|
+
await x.mapAsync(GPUMapMode.READ);
|
|
132
|
+
const m = x.getMappedRange(), g = this.pixelBuffer ?? new Uint8Array(this.config.width * this.config.height * 4), u = new Uint8Array(m);
|
|
133
|
+
for (let f = 0; f < this.config.height; f++) {
|
|
134
|
+
const k = f * this.readbackBytesPerRow, U = f * this.readbackActualBytesPerRow;
|
|
135
|
+
g.set(
|
|
136
|
+
u.subarray(k, k + this.readbackActualBytesPerRow),
|
|
137
|
+
U
|
|
181
138
|
);
|
|
182
139
|
}
|
|
183
|
-
|
|
184
|
-
return new VideoFrame(pixelData, {
|
|
140
|
+
return x.unmap(), new VideoFrame(g, {
|
|
185
141
|
format: "RGBA",
|
|
186
142
|
codedWidth: this.config.width,
|
|
187
143
|
codedHeight: this.config.height,
|
|
188
|
-
timestamp
|
|
144
|
+
timestamp: r
|
|
189
145
|
});
|
|
190
146
|
}
|
|
191
147
|
/**
|
|
192
|
-
* Create input texture
|
|
148
|
+
* Create input texture (TypeGPU; per official docs: sampled + render for .write(image/VideoFrame)).
|
|
193
149
|
*/
|
|
194
|
-
createInputTexture(
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
return root["~unstable"].createTexture({ size, format }).$usage("sampled");
|
|
150
|
+
createInputTexture(t, o, r) {
|
|
151
|
+
const e = [o, r];
|
|
152
|
+
return t["~unstable"].createTexture({ size: e, format: "rgba8unorm" }).$usage("sampled", "render");
|
|
198
153
|
}
|
|
199
154
|
/**
|
|
200
|
-
* Create output texture
|
|
155
|
+
* Create output storage texture (TypeGPU; type-safe with layout.$)
|
|
201
156
|
*/
|
|
202
|
-
createOutputTexture(
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
return root["~unstable"].createTexture({ size, format }).$usage("storage");
|
|
157
|
+
createOutputTexture(t, o, r) {
|
|
158
|
+
const e = [o, r];
|
|
159
|
+
return t["~unstable"].createTexture({ size: e, format: "rgba8unorm" }).$usage("storage");
|
|
206
160
|
}
|
|
207
161
|
/**
|
|
208
162
|
* Calculate bytes per row with proper alignment (256-byte alignment for WebGPU)
|
|
209
163
|
*/
|
|
210
|
-
calculateBytesPerRow(
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
return Math.ceil(unalignedBytesPerRow / 256) * 256;
|
|
164
|
+
calculateBytesPerRow(t) {
|
|
165
|
+
const r = t * 4;
|
|
166
|
+
return Math.ceil(r / 256) * 256;
|
|
214
167
|
}
|
|
215
168
|
/**
|
|
216
169
|
* Create or recreate readback buffer for GPU to CPU data transfer
|
|
217
170
|
*/
|
|
218
|
-
createReadbackBuffer(
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
size: bufferSize,
|
|
171
|
+
createReadbackBuffer(t, o, r) {
|
|
172
|
+
const n = this.calculateBytesPerRow(o) * r;
|
|
173
|
+
return t.createBuffer({
|
|
174
|
+
size: n,
|
|
223
175
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
224
176
|
});
|
|
225
177
|
}
|
|
@@ -229,231 +181,114 @@ var Fisheye = class _Fisheye {
|
|
|
229
181
|
* @param frame - Input VideoFrame with fisheye distortion
|
|
230
182
|
* @returns Dewarped VideoFrame
|
|
231
183
|
*/
|
|
232
|
-
async dewarp(
|
|
233
|
-
await this.initialize()
|
|
234
|
-
if (!this.root || !this.uniformBuffer) {
|
|
184
|
+
async dewarp(t) {
|
|
185
|
+
if (await this.initialize(), !this.root || !this.uniformBuffer)
|
|
235
186
|
throw new Error("GPU resources not initialized");
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
this.readbackActualBytesPerRow = this.config.width * 4;
|
|
255
|
-
this.pixelBuffer = new Uint8Array(this.config.width * this.config.height * 4);
|
|
256
|
-
this.readbackBuffers = [
|
|
257
|
-
this.createReadbackBuffer(device, this.config.width, this.config.height),
|
|
258
|
-
this.createReadbackBuffer(device, this.config.width, this.config.height)
|
|
259
|
-
];
|
|
260
|
-
this.readbackIndex = 0;
|
|
261
|
-
this.readbackHasData = [false, false];
|
|
262
|
-
this.outputTextureSize = [this.config.width, this.config.height];
|
|
263
|
-
bindGroupDirty = true;
|
|
264
|
-
}
|
|
265
|
-
const inputTexture = this.inputTexture;
|
|
266
|
-
const outputTexture = this.outputTexture;
|
|
267
|
-
inputTexture.write(frame);
|
|
268
|
-
if (bindGroupDirty || !this.bindGroup) {
|
|
269
|
-
this.bindGroup = root.createBindGroup(fisheyeLayout, {
|
|
270
|
-
inputTexture: this.inputView ?? _Fisheye.createInputView(inputTexture),
|
|
271
|
-
outputTexture: this.outputView ?? _Fisheye.createOutputView(outputTexture),
|
|
272
|
-
uniforms: this.uniformBuffer
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
const bindGroup = this.bindGroup;
|
|
276
|
-
const dewarpPipeline = this.dewarpPipeline;
|
|
277
|
-
if (!dewarpPipeline) {
|
|
278
|
-
throw new Error("Compute pipeline not initialized");
|
|
279
|
-
}
|
|
280
|
-
dewarpPipeline.with(bindGroup).dispatchThreads(this.config.width, this.config.height);
|
|
281
|
-
return this.readbackToVideoFrame(device, root, outputTexture, frame.timestamp);
|
|
187
|
+
const o = this.root, r = o.device;
|
|
188
|
+
(!this.inputTexture || this.inputTextureSize[0] !== t.displayWidth || this.inputTextureSize[1] !== t.displayHeight) && (this.inputTexture?.destroy(), this.inputTexture = this.createInputTexture(o, t.displayWidth, t.displayHeight), this.inputTextureSize = [t.displayWidth, t.displayHeight], this.bindGroup = null), (!this.outputTexture || this.outputTextureSize[0] !== this.config.width || this.outputTextureSize[1] !== this.config.height) && (this.outputTexture?.destroy(), this.readbackBuffers?.[0]?.destroy(), this.readbackBuffers?.[1]?.destroy(), this.outputTexture = this.createOutputTexture(o, this.config.width, this.config.height), this.readbackBytesPerRow = this.calculateBytesPerRow(this.config.width), this.readbackActualBytesPerRow = this.config.width * 4, this.pixelBuffer = new Uint8Array(this.config.width * this.config.height * 4), this.readbackBuffers = [
|
|
189
|
+
this.createReadbackBuffer(r, this.config.width, this.config.height),
|
|
190
|
+
this.createReadbackBuffer(r, this.config.width, this.config.height)
|
|
191
|
+
], this.readbackIndex = 0, this.readbackHasData = [!1, !1], this.outputTextureSize = [this.config.width, this.config.height], this.bindGroup = null);
|
|
192
|
+
const e = this.inputTexture, n = this.outputTexture;
|
|
193
|
+
if (!e || !n) throw new Error("Textures not initialized");
|
|
194
|
+
e.write(t), this.uniformInputWidth = t.displayWidth, this.uniformInputHeight = t.displayHeight, this.updateUniforms(), this.bindGroup || (this.bindGroup = o.createBindGroup(P, {
|
|
195
|
+
inputTexture: e,
|
|
196
|
+
outputTexture: n,
|
|
197
|
+
uniforms: this.uniformBuffer
|
|
198
|
+
}));
|
|
199
|
+
const c = this.bindGroup, a = this.dewarpPipeline;
|
|
200
|
+
if (!a || !n)
|
|
201
|
+
throw new Error("Compute pipeline or output texture not initialized");
|
|
202
|
+
a.with(c).dispatchThreads(this.config.width, this.config.height);
|
|
203
|
+
const p = o.unwrap(n);
|
|
204
|
+
return this.readbackToVideoFrame(r, p, t.timestamp);
|
|
282
205
|
}
|
|
283
206
|
/**
|
|
284
207
|
* Update configuration
|
|
285
208
|
*/
|
|
286
|
-
updateConfig(
|
|
287
|
-
this.config = this.applyDefaults({ ...this.config, ...
|
|
288
|
-
this.updateUniforms();
|
|
289
|
-
if (options.width || options.height) {
|
|
290
|
-
this.outputTexture?.destroy();
|
|
291
|
-
this.readbackBuffers?.[0]?.destroy();
|
|
292
|
-
this.readbackBuffers?.[1]?.destroy();
|
|
293
|
-
this.outputTexture = null;
|
|
294
|
-
this.readbackBuffers = null;
|
|
295
|
-
this.readbackIndex = 0;
|
|
296
|
-
this.readbackHasData = [false, false];
|
|
297
|
-
this.outputTextureSize = [0, 0];
|
|
298
|
-
this.outputView = null;
|
|
299
|
-
this.bindGroup = null;
|
|
300
|
-
this.readbackBytesPerRow = 0;
|
|
301
|
-
this.readbackActualBytesPerRow = 0;
|
|
302
|
-
this.pixelBuffer = null;
|
|
303
|
-
}
|
|
209
|
+
updateConfig(t) {
|
|
210
|
+
this.config = this.applyDefaults({ ...this.config, ...t }), this.updateUniforms(), (t.width || t.height) && (this.outputTexture?.destroy(), this.readbackBuffers?.[0]?.destroy(), this.readbackBuffers?.[1]?.destroy(), this.outputTexture = null, this.readbackBuffers = null, this.readbackIndex = 0, this.readbackHasData = [!1, !1], this.outputTextureSize = [0, 0], this.readbackBytesPerRow = 0, this.readbackActualBytesPerRow = 0, this.pixelBuffer = null);
|
|
304
211
|
}
|
|
305
212
|
/**
|
|
306
213
|
* Clean up GPU resources
|
|
307
214
|
*/
|
|
308
215
|
destroy() {
|
|
309
|
-
this.inputTexture?.destroy();
|
|
310
|
-
this.outputTexture?.destroy();
|
|
311
|
-
this.readbackBuffers?.[0]?.destroy();
|
|
312
|
-
this.readbackBuffers?.[1]?.destroy();
|
|
313
|
-
this.root?.destroy();
|
|
314
|
-
this.inputTexture = null;
|
|
315
|
-
this.outputTexture = null;
|
|
316
|
-
this.readbackBuffers = null;
|
|
317
|
-
this.readbackIndex = 0;
|
|
318
|
-
this.readbackHasData = [false, false];
|
|
319
|
-
this.uniformBuffer = null;
|
|
320
|
-
this.root = null;
|
|
321
|
-
this.inputView = null;
|
|
322
|
-
this.outputView = null;
|
|
323
|
-
this.bindGroup = null;
|
|
324
|
-
this.dewarpPipeline = null;
|
|
325
|
-
this.readbackBytesPerRow = 0;
|
|
326
|
-
this.readbackActualBytesPerRow = 0;
|
|
327
|
-
this.pixelBuffer = null;
|
|
328
|
-
this.inputTextureSize = [0, 0];
|
|
329
|
-
this.outputTextureSize = [0, 0];
|
|
216
|
+
this.inputTexture?.destroy(), this.outputTexture?.destroy(), this.readbackBuffers?.[0]?.destroy(), this.readbackBuffers?.[1]?.destroy(), this.root?.destroy(), this.inputTexture = null, this.outputTexture = null, this.readbackBuffers = null, this.readbackIndex = 0, this.readbackHasData = [!1, !1], this.uniformBuffer = null, this.root = null, this.bindGroup = null, this.dewarpPipeline = null, this.readbackBytesPerRow = 0, this.readbackActualBytesPerRow = 0, this.pixelBuffer = null, this.inputTextureSize = [0, 0], this.outputTextureSize = [0, 0];
|
|
330
217
|
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// src/utils.ts
|
|
334
|
-
function createVideoFrameFromYUV(data, options) {
|
|
218
|
+
}
|
|
219
|
+
function O(s, t) {
|
|
335
220
|
const {
|
|
336
|
-
format,
|
|
337
|
-
width,
|
|
338
|
-
height,
|
|
339
|
-
timestamp,
|
|
340
|
-
duration,
|
|
341
|
-
displayWidth,
|
|
342
|
-
displayHeight,
|
|
343
|
-
colorSpace,
|
|
344
|
-
transfer
|
|
345
|
-
} =
|
|
346
|
-
if (
|
|
221
|
+
format: o,
|
|
222
|
+
width: r,
|
|
223
|
+
height: e,
|
|
224
|
+
timestamp: n,
|
|
225
|
+
duration: c,
|
|
226
|
+
displayWidth: a,
|
|
227
|
+
displayHeight: p,
|
|
228
|
+
colorSpace: l,
|
|
229
|
+
transfer: x
|
|
230
|
+
} = t;
|
|
231
|
+
if (r <= 0 || e <= 0)
|
|
347
232
|
throw new Error("Width and height must be positive integers");
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const actualSize = data instanceof ArrayBuffer ? data.byteLength : data.byteLength;
|
|
351
|
-
if (actualSize < expectedSize) {
|
|
233
|
+
const m = $(o, r, e), g = (s instanceof ArrayBuffer, s.byteLength);
|
|
234
|
+
if (g < m)
|
|
352
235
|
throw new Error(
|
|
353
|
-
`Buffer too small for ${
|
|
236
|
+
`Buffer too small for ${o} format. Expected at least ${m} bytes, got ${g} bytes`
|
|
354
237
|
);
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
timestamp
|
|
238
|
+
const u = {
|
|
239
|
+
format: o,
|
|
240
|
+
codedWidth: r,
|
|
241
|
+
codedHeight: e,
|
|
242
|
+
timestamp: n
|
|
361
243
|
};
|
|
362
|
-
if (duration !== void 0) {
|
|
363
|
-
|
|
244
|
+
if (c !== void 0 && (u.duration = c), a !== void 0 && (u.displayWidth = a), p !== void 0 && (u.displayHeight = p), l !== void 0 && (u.colorSpace = l), x) {
|
|
245
|
+
const f = s instanceof ArrayBuffer ? s : s.buffer;
|
|
246
|
+
u.transfer = [f];
|
|
364
247
|
}
|
|
365
|
-
|
|
366
|
-
init.displayWidth = displayWidth;
|
|
367
|
-
}
|
|
368
|
-
if (displayHeight !== void 0) {
|
|
369
|
-
init.displayHeight = displayHeight;
|
|
370
|
-
}
|
|
371
|
-
if (colorSpace !== void 0) {
|
|
372
|
-
init.colorSpace = colorSpace;
|
|
373
|
-
}
|
|
374
|
-
if (transfer) {
|
|
375
|
-
const buffer = data instanceof ArrayBuffer ? data : data.buffer;
|
|
376
|
-
init.transfer = [buffer];
|
|
377
|
-
}
|
|
378
|
-
return new VideoFrame(data, init);
|
|
248
|
+
return new VideoFrame(s, u);
|
|
379
249
|
}
|
|
380
|
-
function
|
|
381
|
-
if (
|
|
382
|
-
throw new Error(`Unsupported format: ${
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
const Y_R = 0.299;
|
|
389
|
-
const Y_G = 0.587;
|
|
390
|
-
const Y_B = 0.114;
|
|
391
|
-
const U_R = -0.169;
|
|
392
|
-
const U_G = -0.331;
|
|
393
|
-
const U_B = 0.5;
|
|
394
|
-
const V_R = 0.5;
|
|
395
|
-
const V_G = -0.419;
|
|
396
|
-
const V_B = -0.081;
|
|
397
|
-
const yPlane = yuvData.subarray(0, lumaSize);
|
|
398
|
-
const uPlane = yuvData.subarray(lumaSize, lumaSize + chromaSize);
|
|
399
|
-
const vPlane = yuvData.subarray(lumaSize + chromaSize, yuvSize);
|
|
400
|
-
for (let y = 0; y < height; y++) {
|
|
401
|
-
for (let x = 0; x < width; x++) {
|
|
402
|
-
const rgbaIdx = (y * width + x) * 4;
|
|
403
|
-
const r = rgbaData[rgbaIdx];
|
|
404
|
-
const g = rgbaData[rgbaIdx + 1];
|
|
405
|
-
const b = rgbaData[rgbaIdx + 2];
|
|
406
|
-
const yVal = Y_R * r + Y_G * g + Y_B * b;
|
|
407
|
-
yPlane[y * width + x] = Math.round(Math.max(0, Math.min(255, yVal)));
|
|
250
|
+
function N(s, t, o, r = "I420") {
|
|
251
|
+
if (r !== "I420")
|
|
252
|
+
throw new Error(`Unsupported format: ${r}. Only I420 is currently supported.`);
|
|
253
|
+
const e = t * o, n = t / 2 * (o / 2), c = e + n * 2, a = new Uint8Array(c), p = 0.299, l = 0.587, x = 0.114, m = -0.169, g = -0.331, u = 0.5, f = 0.5, k = -0.419, U = -0.081, A = a.subarray(0, e), H = a.subarray(e, e + n), G = a.subarray(e + n, c);
|
|
254
|
+
for (let d = 0; d < o; d++)
|
|
255
|
+
for (let h = 0; h < t; h++) {
|
|
256
|
+
const y = (d * t + h) * 4, T = s[y], R = s[y + 1], _ = s[y + 2], S = p * T + l * R + x * _;
|
|
257
|
+
A[d * t + h] = Math.round(Math.max(0, Math.min(255, S)));
|
|
408
258
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
let
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const srcX = x * 2 + dx;
|
|
417
|
-
const srcY = y * 2 + dy;
|
|
418
|
-
const rgbaIdx = (srcY * width + srcX) * 4;
|
|
419
|
-
const r = rgbaData[rgbaIdx];
|
|
420
|
-
const g = rgbaData[rgbaIdx + 1];
|
|
421
|
-
const b = rgbaData[rgbaIdx + 2];
|
|
422
|
-
const uVal = U_R * r + U_G * g + U_B * b + 128;
|
|
423
|
-
const vVal = V_R * r + V_G * g + V_B * b + 128;
|
|
424
|
-
uSum += uVal;
|
|
425
|
-
vSum += vVal;
|
|
259
|
+
for (let d = 0; d < o / 2; d++)
|
|
260
|
+
for (let h = 0; h < t / 2; h++) {
|
|
261
|
+
let y = 0, T = 0;
|
|
262
|
+
for (let B = 0; B < 2; B++)
|
|
263
|
+
for (let v = 0; v < 2; v++) {
|
|
264
|
+
const w = h * 2 + v, z = ((d * 2 + B) * t + w) * 4, Y = s[z], W = s[z + 1], E = s[z + 2], V = m * Y + g * W + u * E + 128, F = f * Y + k * W + U * E + 128;
|
|
265
|
+
y += V, T += F;
|
|
426
266
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const vAvg = vSum / 4;
|
|
430
|
-
const chromaIdx = y * (width / 2) + x;
|
|
431
|
-
uPlane[chromaIdx] = Math.round(Math.max(0, Math.min(255, uAvg)));
|
|
432
|
-
vPlane[chromaIdx] = Math.round(Math.max(0, Math.min(255, vAvg)));
|
|
267
|
+
const R = y / 4, _ = T / 4, S = d * (t / 2) + h;
|
|
268
|
+
H[S] = Math.round(Math.max(0, Math.min(255, R))), G[S] = Math.round(Math.max(0, Math.min(255, _)));
|
|
433
269
|
}
|
|
434
|
-
|
|
435
|
-
return yuvData;
|
|
270
|
+
return a;
|
|
436
271
|
}
|
|
437
|
-
function
|
|
438
|
-
const
|
|
439
|
-
switch (
|
|
272
|
+
function $(s, t, o) {
|
|
273
|
+
const r = t * o;
|
|
274
|
+
switch (s) {
|
|
440
275
|
case "I420":
|
|
441
276
|
case "NV12":
|
|
442
|
-
return
|
|
277
|
+
return r + r / 2;
|
|
443
278
|
case "I420A":
|
|
444
|
-
return
|
|
279
|
+
return r * 2 + r / 2;
|
|
445
280
|
case "I422":
|
|
446
|
-
return
|
|
281
|
+
return r * 2;
|
|
447
282
|
case "I444":
|
|
448
|
-
return
|
|
283
|
+
return r * 3;
|
|
449
284
|
default:
|
|
450
|
-
throw new Error(`Unsupported YUV format: ${
|
|
285
|
+
throw new Error(`Unsupported YUV format: ${s}`);
|
|
451
286
|
}
|
|
452
287
|
}
|
|
453
288
|
export {
|
|
454
|
-
Fisheye,
|
|
455
|
-
calculateYUVDataSize,
|
|
456
|
-
convertRGBAtoYUV,
|
|
457
|
-
createVideoFrameFromYUV
|
|
289
|
+
X as Fisheye,
|
|
290
|
+
$ as calculateYUVDataSize,
|
|
291
|
+
N as convertRGBAtoYUV,
|
|
292
|
+
O as createVideoFrameFromYUV
|
|
458
293
|
};
|
|
459
|
-
//# sourceMappingURL=index.js.map
|
|
294
|
+
//# sourceMappingURL=index.js.map
|