@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.
Files changed (41) hide show
  1. package/README.md +2 -2
  2. package/lib/additional.d.ts +1 -0
  3. package/lib/android-bridge-message-handler.d.ts +11 -0
  4. package/lib/android-bridge-message-handler.js +167 -0
  5. package/lib/array-from-string.d.ts +2 -0
  6. package/lib/array-from-string.js +48 -0
  7. package/lib/bridged-camera-source.d.ts +39 -0
  8. package/lib/bridged-camera-source.js +383 -0
  9. package/lib/bridged-message-parser.d.ts +12 -0
  10. package/lib/bridged-message-parser.js +56 -0
  11. package/lib/bridged-message.d.ts +64 -0
  12. package/lib/bridged-message.js +1 -0
  13. package/lib/bridged-world-tracker.d.ts +20 -0
  14. package/lib/bridged-world-tracker.js +426 -0
  15. package/lib/camera-source-map.d.ts +2 -1
  16. package/lib/camera-source-map.js +4 -1
  17. package/lib/drawmesh.d.ts +14 -0
  18. package/lib/drawmesh.js +123 -0
  19. package/lib/gen/zappar-client.js +12 -0
  20. package/lib/gen/zappar.d.ts +16 -0
  21. package/lib/index-standalone.js +1 -1
  22. package/lib/native.js +61 -15
  23. package/lib/options.d.ts +1 -0
  24. package/lib/permission.js +6 -0
  25. package/lib/pipeline.js +2 -1
  26. package/lib/profile.js +2 -1
  27. package/lib/source.d.ts +1 -0
  28. package/lib/version.d.ts +1 -1
  29. package/lib/version.js +1 -1
  30. package/lib/yuv-conversion-gl.d.ts +44 -0
  31. package/lib/yuv-conversion-gl.js +416 -0
  32. package/lib/zappar-cv.js +1 -1
  33. package/lib/zappar-cv.wasm +0 -0
  34. package/package.json +6 -16
  35. package/umd/287.zappar-cv.js +1 -0
  36. package/umd/{7fd693559466ec5f412e.wasm → 641e1456d6d56783d581.wasm} +0 -0
  37. package/umd/867.zappar-cv.js +1 -1
  38. package/umd/zappar-cv-ceres.worker.js +1 -0
  39. package/umd/zappar-cv.js +1 -1
  40. package/umd/zappar-cv.worker.js +1 -1
  41. 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
+ `;