@zappar/zappar-cv 3.0.1-beta.8 → 3.1.0-beta.2
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 +2 -2
- package/lib/additional.d.ts +1 -0
- package/lib/android-bridge-message-handler.d.ts +11 -0
- package/lib/android-bridge-message-handler.js +167 -0
- package/lib/array-from-string.d.ts +2 -0
- package/lib/array-from-string.js +48 -0
- package/lib/bridged-camera-source.d.ts +39 -0
- package/lib/bridged-camera-source.js +383 -0
- package/lib/bridged-message-parser.d.ts +12 -0
- package/lib/bridged-message-parser.js +56 -0
- package/lib/bridged-message.d.ts +64 -0
- package/lib/bridged-message.js +1 -0
- package/lib/bridged-world-tracker.d.ts +20 -0
- package/lib/bridged-world-tracker.js +426 -0
- package/lib/camera-source-map.d.ts +2 -1
- package/lib/camera-source-map.js +4 -1
- package/lib/drawmesh.d.ts +14 -0
- package/lib/drawmesh.js +123 -0
- package/lib/gen/zappar-client.js +12 -0
- package/lib/gen/zappar.d.ts +16 -0
- package/lib/index-standalone.js +1 -1
- package/lib/native.js +61 -15
- package/lib/options.d.ts +1 -0
- package/lib/permission.js +6 -0
- package/lib/pipeline.js +2 -1
- package/lib/profile.js +2 -1
- package/lib/source.d.ts +1 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/yuv-conversion-gl.d.ts +44 -0
- package/lib/yuv-conversion-gl.js +416 -0
- package/lib/zappar-cv.js +1 -1
- package/lib/zappar-cv.wasm +0 -0
- package/package.json +6 -16
- package/umd/287.zappar-cv.js +1 -0
- package/umd/{7fd693559466ec5f412e.wasm → 641e1456d6d56783d581.wasm} +0 -0
- package/umd/867.zappar-cv.js +1 -1
- package/umd/zappar-cv-ceres.worker.js +1 -0
- package/umd/zappar-cv.js +1 -1
- package/umd/zappar-cv.worker.js +1 -1
- package/umd/751.zappar-cv.js +0 -1
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import { GLStateManager } from "./gl-state-manager";
|
|
2
|
+
import { compileShader, linkProgram } from "./shader";
|
|
3
|
+
import { zcout } from "./loglevel";
|
|
4
|
+
import { getSharedTracer } from "./tracing/sharedtracer";
|
|
5
|
+
// Some no-op tracing helpers for concise code and good dead code removal in bundlers
|
|
6
|
+
let tracer = null;
|
|
7
|
+
let traceStart = (name) => { };
|
|
8
|
+
let traceEnd = () => { };
|
|
9
|
+
if (!(typeof Z_TRACING)) {
|
|
10
|
+
tracer = getSharedTracer();
|
|
11
|
+
traceStart = (name) => { tracer.start(name); };
|
|
12
|
+
traceEnd = () => { tracer.end(); };
|
|
13
|
+
}
|
|
14
|
+
export var UvLayout;
|
|
15
|
+
(function (UvLayout) {
|
|
16
|
+
UvLayout[UvLayout["INTERLEAVED_UV"] = 0] = "INTERLEAVED_UV";
|
|
17
|
+
UvLayout[UvLayout["INTERLEAVED_VU"] = 1] = "INTERLEAVED_VU";
|
|
18
|
+
UvLayout[UvLayout["PLANAR_UV"] = 2] = "PLANAR_UV";
|
|
19
|
+
})(UvLayout || (UvLayout = {}));
|
|
20
|
+
export class YUVConversionGL {
|
|
21
|
+
constructor(_gl) {
|
|
22
|
+
this._gl = _gl;
|
|
23
|
+
this._yTexture = null;
|
|
24
|
+
this._uvTexture = null;
|
|
25
|
+
this._uvTextureSinglePlane = false;
|
|
26
|
+
this._vTexture = null;
|
|
27
|
+
this._framebufferId = null;
|
|
28
|
+
this._vao = null;
|
|
29
|
+
this._conversionShaders = [];
|
|
30
|
+
this._isWebGL2 = false;
|
|
31
|
+
this._useVao = false;
|
|
32
|
+
this._isWebGL2 = _gl.getParameter(_gl.VERSION).indexOf("WebGL 2") >= 0;
|
|
33
|
+
this._useVao = true;
|
|
34
|
+
if (!this._isWebGL2) {
|
|
35
|
+
this._vaoExtension = this._gl.getExtension("OES_vertex_array_object");
|
|
36
|
+
if (this._vaoExtension == null) {
|
|
37
|
+
// We'll have to query and reset the vertex attribute state manually :(
|
|
38
|
+
this._useVao = false;
|
|
39
|
+
this._instancedArraysExtension = this._gl.getExtension("ANGLE_instanced_arrays");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const gl2 = _gl; // Must check _isWebGL2 before use
|
|
43
|
+
this._oneComponentInternalFormat = this._isWebGL2 ? gl2.R8 : _gl.ALPHA;
|
|
44
|
+
this._oneComponentFormat = this._isWebGL2 ? gl2.RED : _gl.ALPHA;
|
|
45
|
+
this._twoComponentInternalFormat = this._isWebGL2 ? gl2.RG8 : _gl.LUMINANCE_ALPHA;
|
|
46
|
+
this._twoComponentFormat = this._isWebGL2 ? gl2.RG : _gl.LUMINANCE_ALPHA;
|
|
47
|
+
}
|
|
48
|
+
resetGLContext() {
|
|
49
|
+
this._yTexture = null;
|
|
50
|
+
this._uvTexture = null;
|
|
51
|
+
this._vTexture = null;
|
|
52
|
+
this._framebufferId = null;
|
|
53
|
+
this._vao = null;
|
|
54
|
+
this._vertexBuffer = undefined;
|
|
55
|
+
this._conversionShaders = [];
|
|
56
|
+
}
|
|
57
|
+
destroy() {
|
|
58
|
+
this.resetGLContext();
|
|
59
|
+
}
|
|
60
|
+
yuvToTexture(y, uv, uvLayout, destination) {
|
|
61
|
+
const gl = this._gl;
|
|
62
|
+
const gl2 = gl; // Must check _isWebGL2 before use
|
|
63
|
+
const glStateManager = GLStateManager.get(gl);
|
|
64
|
+
glStateManager.push();
|
|
65
|
+
const reenableScissorTest = gl.isEnabled(gl.SCISSOR_TEST);
|
|
66
|
+
const reenableDepthTest = gl.isEnabled(gl.DEPTH_TEST);
|
|
67
|
+
const reenableBlend = gl.isEnabled(gl.BLEND);
|
|
68
|
+
const reenableCullFace = gl.isEnabled(gl.CULL_FACE);
|
|
69
|
+
const reenableStencilTest = gl.isEnabled(gl.STENCIL_TEST);
|
|
70
|
+
const previousUnpackFlip = gl.getParameter(gl.UNPACK_FLIP_Y_WEBGL);
|
|
71
|
+
const previousActiveTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
|
|
72
|
+
const previousProgram = gl.getParameter(gl.CURRENT_PROGRAM);
|
|
73
|
+
const previousBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
|
|
74
|
+
const previousBoundArrayBuffer = gl.getParameter(gl.ARRAY_BUFFER_BINDING);
|
|
75
|
+
let previousVAO = null;
|
|
76
|
+
if (this._isWebGL2) {
|
|
77
|
+
previousVAO = gl2.getParameter(gl2.VERTEX_ARRAY_BINDING);
|
|
78
|
+
}
|
|
79
|
+
else if (this._vaoExtension) {
|
|
80
|
+
previousVAO = gl.getParameter(this._vaoExtension.VERTEX_ARRAY_BINDING_OES);
|
|
81
|
+
}
|
|
82
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
83
|
+
const previousBoundTexture0 = gl.getParameter(gl.TEXTURE_BINDING_2D);
|
|
84
|
+
// We've stored all the GL state we will need to restore, so this is the
|
|
85
|
+
// first moment we can initialize our WebGL objects safely
|
|
86
|
+
if (!this._framebufferId)
|
|
87
|
+
this._prepareContext();
|
|
88
|
+
let isPlanarUv = (uvLayout === UvLayout.PLANAR_UV && !!uv.dataVPlane);
|
|
89
|
+
this._prepareTextures(y, uv, isPlanarUv);
|
|
90
|
+
// Get the appropriate shader for the uv layout
|
|
91
|
+
let conversionShader = this._conversionShaders[uvLayout];
|
|
92
|
+
if (!conversionShader) {
|
|
93
|
+
traceStart("YUV: Prepare conversion shader");
|
|
94
|
+
this._prepareConversionShader(uvLayout);
|
|
95
|
+
conversionShader = this._conversionShaders[uvLayout];
|
|
96
|
+
traceEnd();
|
|
97
|
+
}
|
|
98
|
+
if (!conversionShader || !this._vertexBuffer || !this._yTexture || !this._uvTexture || (isPlanarUv && !this._vTexture)) {
|
|
99
|
+
// Didn't fully initialize our WebGL objects, bail out but reset the few bits we've changed
|
|
100
|
+
gl.bindTexture(gl.TEXTURE_2D, previousBoundTexture0);
|
|
101
|
+
gl.activeTexture(previousActiveTexture);
|
|
102
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, previousBoundArrayBuffer);
|
|
103
|
+
if (this._isWebGL2) {
|
|
104
|
+
gl2.bindVertexArray(previousVAO);
|
|
105
|
+
}
|
|
106
|
+
else if (this._vaoExtension) {
|
|
107
|
+
this._vaoExtension.bindVertexArrayOES(previousVAO);
|
|
108
|
+
}
|
|
109
|
+
gl.useProgram(previousProgram);
|
|
110
|
+
glStateManager.pop();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const aPositionLoc = conversionShader.aPositionLoc;
|
|
114
|
+
let prevPosAttribState = undefined;
|
|
115
|
+
if (!this._useVao) {
|
|
116
|
+
// Capture previous vertex attribute state for the location we're using for positions
|
|
117
|
+
traceStart('getVertexAttribState');
|
|
118
|
+
prevPosAttribState = this._getVertexAttribState(gl, aPositionLoc);
|
|
119
|
+
traceEnd();
|
|
120
|
+
}
|
|
121
|
+
// Global state
|
|
122
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
123
|
+
gl.disable(gl.DEPTH_TEST);
|
|
124
|
+
gl.disable(gl.BLEND);
|
|
125
|
+
gl.disable(gl.CULL_FACE);
|
|
126
|
+
gl.disable(gl.STENCIL_TEST);
|
|
127
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
|
128
|
+
// Upload the Y texture data
|
|
129
|
+
gl.bindTexture(gl.TEXTURE_2D, this._yTexture.texture);
|
|
130
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, y.width, y.height, this._yTexture.format, gl.UNSIGNED_BYTE, y.data);
|
|
131
|
+
// Upload UV plane
|
|
132
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
133
|
+
const previousBoundTexture1 = gl.getParameter(gl.TEXTURE_BINDING_2D);
|
|
134
|
+
gl.bindTexture(gl.TEXTURE_2D, this._uvTexture.texture);
|
|
135
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, uv.width, uv.height, this._uvTexture.format, gl.UNSIGNED_BYTE, uv.data);
|
|
136
|
+
let previousBoundTexture2;
|
|
137
|
+
if (isPlanarUv) {
|
|
138
|
+
gl.activeTexture(gl.TEXTURE2);
|
|
139
|
+
previousBoundTexture2 = gl.getParameter(gl.TEXTURE_BINDING_2D);
|
|
140
|
+
gl.bindTexture(gl.TEXTURE_2D, this._vTexture.texture);
|
|
141
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, uv.width, uv.height, this._vTexture.format, gl.UNSIGNED_BYTE, uv.dataVPlane);
|
|
142
|
+
}
|
|
143
|
+
// Bind framebuffer and set the destination texture (caller must ensure its size matches the Y data)
|
|
144
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebufferId);
|
|
145
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, destination, 0);
|
|
146
|
+
gl.viewport(0, 0, y.width, y.height);
|
|
147
|
+
// We'll be replacing all the content - clear is a good hint for this on mobile
|
|
148
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
149
|
+
// Set up bindings for vertex attributes
|
|
150
|
+
if (this._useVao) {
|
|
151
|
+
if (this._isWebGL2) {
|
|
152
|
+
gl2.bindVertexArray(this._vao);
|
|
153
|
+
}
|
|
154
|
+
else if (this._vaoExtension) {
|
|
155
|
+
this._vaoExtension.bindVertexArrayOES(this._vao);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
|
|
160
|
+
gl.vertexAttribPointer(aPositionLoc, 2, gl.FLOAT, false, 0, 0);
|
|
161
|
+
if (prevPosAttribState && prevPosAttribState.divisor != 0) {
|
|
162
|
+
if (this._isWebGL2) {
|
|
163
|
+
gl2.vertexAttribDivisor(aPositionLoc, 0);
|
|
164
|
+
}
|
|
165
|
+
else if (this._instancedArraysExtension) {
|
|
166
|
+
this._instancedArraysExtension.vertexAttribDivisorANGLE(aPositionLoc, 0);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
gl.enableVertexAttribArray(aPositionLoc);
|
|
170
|
+
}
|
|
171
|
+
// Tell WebGL to use our program when drawing
|
|
172
|
+
gl.useProgram(conversionShader.program);
|
|
173
|
+
// Do the drawing...
|
|
174
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
175
|
+
// Remove the destination texture from the framebuffer
|
|
176
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0);
|
|
177
|
+
// Reset the state
|
|
178
|
+
if (reenableBlend)
|
|
179
|
+
gl.enable(gl.BLEND);
|
|
180
|
+
if (reenableCullFace)
|
|
181
|
+
gl.enable(gl.CULL_FACE);
|
|
182
|
+
if (reenableDepthTest)
|
|
183
|
+
gl.enable(gl.DEPTH_TEST);
|
|
184
|
+
if (reenableScissorTest)
|
|
185
|
+
gl.enable(gl.SCISSOR_TEST);
|
|
186
|
+
if (reenableStencilTest)
|
|
187
|
+
gl.enable(gl.STENCIL_TEST);
|
|
188
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, previousUnpackFlip);
|
|
189
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, previousBoundFramebuffer);
|
|
190
|
+
if (isPlanarUv) {
|
|
191
|
+
gl.bindTexture(gl.TEXTURE_2D, previousBoundTexture2);
|
|
192
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
193
|
+
}
|
|
194
|
+
gl.bindTexture(gl.TEXTURE_2D, previousBoundTexture1);
|
|
195
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
196
|
+
gl.bindTexture(gl.TEXTURE_2D, previousBoundTexture0);
|
|
197
|
+
gl.activeTexture(previousActiveTexture);
|
|
198
|
+
if (this._useVao) {
|
|
199
|
+
if (this._isWebGL2) {
|
|
200
|
+
gl2.bindVertexArray(previousVAO);
|
|
201
|
+
}
|
|
202
|
+
else if (this._vaoExtension) {
|
|
203
|
+
this._vaoExtension.bindVertexArrayOES(previousVAO);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
else if (prevPosAttribState) {
|
|
207
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, prevPosAttribState.bufferBinding);
|
|
208
|
+
gl.vertexAttribPointer(aPositionLoc, prevPosAttribState.size, prevPosAttribState.type, prevPosAttribState.normalized, prevPosAttribState.stride, prevPosAttribState.offset);
|
|
209
|
+
if (prevPosAttribState.divisor != 0) {
|
|
210
|
+
if (this._isWebGL2) {
|
|
211
|
+
gl2.vertexAttribDivisor(aPositionLoc, prevPosAttribState.divisor);
|
|
212
|
+
}
|
|
213
|
+
else if (this._instancedArraysExtension) {
|
|
214
|
+
this._instancedArraysExtension.vertexAttribDivisorANGLE(aPositionLoc, prevPosAttribState.divisor);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (!prevPosAttribState.enabled)
|
|
218
|
+
gl.disableVertexAttribArray(aPositionLoc);
|
|
219
|
+
}
|
|
220
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, previousBoundArrayBuffer);
|
|
221
|
+
gl.useProgram(previousProgram);
|
|
222
|
+
glStateManager.pop();
|
|
223
|
+
}
|
|
224
|
+
_getVertexAttribState(gl, index) {
|
|
225
|
+
let divisor = 0;
|
|
226
|
+
if (this._isWebGL2) {
|
|
227
|
+
traceStart("getWebGL2Divisor");
|
|
228
|
+
divisor = gl.getVertexAttrib(index, gl.VERTEX_ATTRIB_ARRAY_DIVISOR);
|
|
229
|
+
traceEnd();
|
|
230
|
+
}
|
|
231
|
+
else if (this._instancedArraysExtension) {
|
|
232
|
+
traceStart("getExtDivisor");
|
|
233
|
+
divisor = gl.getVertexAttrib(index, this._instancedArraysExtension.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
|
|
234
|
+
traceEnd();
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
size: gl.getVertexAttrib(index, gl.VERTEX_ATTRIB_ARRAY_SIZE),
|
|
238
|
+
type: gl.getVertexAttrib(index, gl.VERTEX_ATTRIB_ARRAY_TYPE),
|
|
239
|
+
normalized: gl.getVertexAttrib(index, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED),
|
|
240
|
+
stride: gl.getVertexAttrib(index, gl.VERTEX_ATTRIB_ARRAY_STRIDE),
|
|
241
|
+
offset: gl.getVertexAttribOffset(index, gl.VERTEX_ATTRIB_ARRAY_POINTER),
|
|
242
|
+
bufferBinding: gl.getVertexAttrib(index, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING),
|
|
243
|
+
enabled: gl.getVertexAttrib(index, gl.VERTEX_ATTRIB_ARRAY_ENABLED),
|
|
244
|
+
divisor
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
_prepareContext() {
|
|
248
|
+
traceStart('YUV: prepareContext');
|
|
249
|
+
const gl = this._gl;
|
|
250
|
+
this._framebufferId = gl.createFramebuffer();
|
|
251
|
+
let vertexData = new Float32Array([
|
|
252
|
+
-1.0, -1.0,
|
|
253
|
+
-1.0, 1.0,
|
|
254
|
+
1.0, -1.0,
|
|
255
|
+
1.0, 1.0
|
|
256
|
+
]);
|
|
257
|
+
this._vertexBuffer = gl.createBuffer();
|
|
258
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
|
|
259
|
+
gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);
|
|
260
|
+
if (this._useVao) {
|
|
261
|
+
if (this._isWebGL2) {
|
|
262
|
+
const gl2 = gl;
|
|
263
|
+
this._vao = gl2.createVertexArray();
|
|
264
|
+
gl2.bindVertexArray(this._vao);
|
|
265
|
+
}
|
|
266
|
+
else if (this._vaoExtension) {
|
|
267
|
+
this._vao = this._vaoExtension.createVertexArrayOES();
|
|
268
|
+
this._vaoExtension.bindVertexArrayOES(this._vao);
|
|
269
|
+
}
|
|
270
|
+
const aPositionLoc = 0; // Ensured with bindAttribLocation
|
|
271
|
+
// _vertexBuffer is already bound to gl.ARRAY_BUFFER
|
|
272
|
+
gl.vertexAttribPointer(aPositionLoc, 2, gl.FLOAT, false, 0, 0);
|
|
273
|
+
gl.enableVertexAttribArray(aPositionLoc);
|
|
274
|
+
}
|
|
275
|
+
traceEnd();
|
|
276
|
+
}
|
|
277
|
+
_prepareConversionShader(uvLayout) {
|
|
278
|
+
const gl = this._gl;
|
|
279
|
+
const isPlanar = (uvLayout === UvLayout.PLANAR_UV);
|
|
280
|
+
let program = gl.createProgram();
|
|
281
|
+
if (!program)
|
|
282
|
+
throw new Error("Couldn't create program");
|
|
283
|
+
let vertexShader = compileShader(gl, gl.VERTEX_SHADER, conversionVsSource);
|
|
284
|
+
const singleChannel = this._isWebGL2 ? 'r' : 'a';
|
|
285
|
+
const twoChannel0 = 'r';
|
|
286
|
+
const twoChannel1 = this._isWebGL2 ? 'g' : 'a';
|
|
287
|
+
let fragmentSource;
|
|
288
|
+
switch (uvLayout) {
|
|
289
|
+
case UvLayout.INTERLEAVED_UV:
|
|
290
|
+
fragmentSource = conversionFsSource(singleChannel, twoChannel0, twoChannel1);
|
|
291
|
+
break;
|
|
292
|
+
case UvLayout.INTERLEAVED_VU:
|
|
293
|
+
fragmentSource = conversionFsSource(singleChannel, twoChannel1, twoChannel0);
|
|
294
|
+
break;
|
|
295
|
+
case UvLayout.PLANAR_UV:
|
|
296
|
+
fragmentSource = conversionFsSourcePlanar(singleChannel);
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
let fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);
|
|
300
|
+
gl.attachShader(program, vertexShader);
|
|
301
|
+
gl.attachShader(program, fragmentShader);
|
|
302
|
+
gl.bindAttribLocation(program, 0, "aPosition");
|
|
303
|
+
linkProgram(gl, program);
|
|
304
|
+
let uYSamplerLoc = gl.getUniformLocation(program, "uYSampler");
|
|
305
|
+
let uUVSamplerLoc = (!isPlanar ? gl.getUniformLocation(program, "uUVSampler") : null);
|
|
306
|
+
let uUSamplerLoc = (isPlanar ? gl.getUniformLocation(program, "uUSampler") : null);
|
|
307
|
+
let uVSamplerLoc = (isPlanar ? gl.getUniformLocation(program, "uVSampler") : null);
|
|
308
|
+
let err = gl.getError();
|
|
309
|
+
if (err != gl.NO_ERROR)
|
|
310
|
+
zcout(`YUVConversion: Error before setting uniforms: 0x${err.toString(16)}`);
|
|
311
|
+
gl.useProgram(program);
|
|
312
|
+
gl.uniform1i(uYSamplerLoc, 0);
|
|
313
|
+
gl.uniform1i(isPlanar ? uUSamplerLoc : uUVSamplerLoc, 1);
|
|
314
|
+
if (isPlanar)
|
|
315
|
+
gl.uniform1i(uVSamplerLoc, 2);
|
|
316
|
+
err = gl.getError();
|
|
317
|
+
if (err != gl.NO_ERROR)
|
|
318
|
+
zcout(`YUVConversion: Error after setting uniforms: 0x${err.toString(16)}`);
|
|
319
|
+
this._conversionShaders[uvLayout] = {
|
|
320
|
+
program,
|
|
321
|
+
aPositionLoc: gl.getAttribLocation(program, "aPosition")
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
_prepareTextures(y, uv, isPlanarUv) {
|
|
325
|
+
const gl = this._gl;
|
|
326
|
+
if (!this._yTexture || this._yTexture.width != y.width || this._yTexture.height != y.height) {
|
|
327
|
+
traceStart("YUV: Creating Y texture");
|
|
328
|
+
if (this._yTexture)
|
|
329
|
+
gl.deleteTexture(this._yTexture.texture);
|
|
330
|
+
this._yTexture = this._createSizedTexture(y.width, y.height, this._oneComponentInternalFormat, this._oneComponentFormat);
|
|
331
|
+
traceEnd();
|
|
332
|
+
}
|
|
333
|
+
if (!this._uvTexture || this._uvTexture.width != uv.width || this._uvTexture.height != uv.height ||
|
|
334
|
+
this._uvTextureSinglePlane != isPlanarUv) {
|
|
335
|
+
traceStart("YUV: Creating UV texture");
|
|
336
|
+
if (this._uvTexture)
|
|
337
|
+
gl.deleteTexture(this._uvTexture.texture);
|
|
338
|
+
const internalFormat = isPlanarUv ? this._oneComponentInternalFormat : this._twoComponentInternalFormat;
|
|
339
|
+
const format = isPlanarUv ? this._oneComponentFormat : this._twoComponentFormat;
|
|
340
|
+
this._uvTexture = this._createSizedTexture(uv.width, uv.height, internalFormat, format);
|
|
341
|
+
this._uvTextureSinglePlane = isPlanarUv;
|
|
342
|
+
traceEnd();
|
|
343
|
+
}
|
|
344
|
+
if (!isPlanarUv)
|
|
345
|
+
return;
|
|
346
|
+
if (!this._vTexture || this._vTexture.width != uv.width || this._vTexture.height != uv.height) {
|
|
347
|
+
traceStart("YUV: Creating V texture");
|
|
348
|
+
if (this._vTexture)
|
|
349
|
+
gl.deleteTexture(this._vTexture.texture);
|
|
350
|
+
this._vTexture = this._createSizedTexture(uv.width, uv.height, this._oneComponentInternalFormat, this._oneComponentFormat);
|
|
351
|
+
traceEnd();
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
_createSizedTexture(width, height, internalFormat, format) {
|
|
355
|
+
const gl = this._gl;
|
|
356
|
+
const texture = gl.createTexture();
|
|
357
|
+
if (!texture)
|
|
358
|
+
return null;
|
|
359
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
360
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
361
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
362
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
363
|
+
if (this._isWebGL2) {
|
|
364
|
+
gl.texStorage2D(gl.TEXTURE_2D, 1, internalFormat, width, height);
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, width, height, 0, format, gl.UNSIGNED_BYTE, null);
|
|
368
|
+
}
|
|
369
|
+
return { texture, width, height, format, internalFormat };
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
let conversionVsSource = `
|
|
373
|
+
attribute vec4 aPosition;
|
|
374
|
+
varying highp vec2 vUV;
|
|
375
|
+
|
|
376
|
+
void main(void) {
|
|
377
|
+
gl_Position = aPosition;
|
|
378
|
+
vUV = 0.5 * (aPosition.xy + vec2(1.0, 1.0));
|
|
379
|
+
}
|
|
380
|
+
`;
|
|
381
|
+
// Fragment shader program
|
|
382
|
+
let conversionFsSource = (yChannel, uChannel, vChannel) => `
|
|
383
|
+
varying highp vec2 vUV;
|
|
384
|
+
|
|
385
|
+
uniform sampler2D uYSampler;
|
|
386
|
+
uniform sampler2D uUVSampler;
|
|
387
|
+
|
|
388
|
+
void main(void) {
|
|
389
|
+
mediump vec4 uv = texture2D(uUVSampler, vUV);
|
|
390
|
+
mediump vec3 ycbcr = vec3(texture2D(uYSampler, vUV).${yChannel}, uv.${uChannel} - 0.5, uv.${vChannel} - 0.5);
|
|
391
|
+
const mediump mat3 ycbcrToRgb = mat3(1.0000, 1.0000, 1.0000,
|
|
392
|
+
0.0000, -0.3441, 1.7720,
|
|
393
|
+
1.4020, -0.7141, 0.0000);
|
|
394
|
+
|
|
395
|
+
gl_FragColor = vec4(ycbcrToRgb * ycbcr, 1.0);
|
|
396
|
+
}
|
|
397
|
+
`;
|
|
398
|
+
let conversionFsSourcePlanar = (channel) => `
|
|
399
|
+
varying highp vec2 vUV;
|
|
400
|
+
|
|
401
|
+
uniform sampler2D uYSampler;
|
|
402
|
+
uniform sampler2D uUSampler;
|
|
403
|
+
uniform sampler2D uVSampler;
|
|
404
|
+
|
|
405
|
+
void main(void) {
|
|
406
|
+
mediump vec3 ycbcr = vec3(
|
|
407
|
+
texture2D(uYSampler, vUV).${channel},
|
|
408
|
+
texture2D(uUSampler, vUV).${channel} - 0.5,
|
|
409
|
+
texture2D(uVSampler, vUV).${channel} - 0.5);
|
|
410
|
+
const mediump mat3 ycbcrToRgb = mat3(1.0000, 1.0000, 1.0000,
|
|
411
|
+
0.0000, -0.3441, 1.7720,
|
|
412
|
+
1.4020, -0.7141, 0.0000);
|
|
413
|
+
|
|
414
|
+
gl_FragColor = vec4(ycbcrToRgb * ycbcr, 1.0);
|
|
415
|
+
}
|
|
416
|
+
`;
|