@pexip/media-processor 20.3.5 → 21.0.0

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 (118) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/api-docs/README.mdx +33 -6
  3. package/api-docs/functions/createBenchmark.mdx +17 -5
  4. package/api-docs/functions/createWindowedStats.mdx +23 -0
  5. package/api-docs/functions/iou.mdx +19 -0
  6. package/api-docs/functions/labelComponents.mdx +20 -0
  7. package/api-docs/functions/nearestPowerOfTwo.mdx +21 -0
  8. package/api-docs/functions/playVideo.mdx +16 -0
  9. package/api-docs/functions/scoreComponent.mdx +22 -0
  10. package/api-docs/functions/setVideoElementSrc.mdx +14 -0
  11. package/api-docs/interfaces/Benchmark.mdx +12 -0
  12. package/api-docs/interfaces/RendererOptions.mdx +26 -9
  13. package/api-docs/interfaces/SegmentationParams.mdx +29 -12
  14. package/api-docs/interfaces/SelectionOptions.mdx +15 -0
  15. package/api-docs/interfaces/Stats.mdx +11 -0
  16. package/api-docs/interfaces/Weights.mdx +12 -0
  17. package/api-docs/type-aliases/OptionalKeys.mdx +10 -0
  18. package/api-docs/variables/BACKGROUND_THRESHOLD.mdx +3 -0
  19. package/api-docs/variables/DOWN_SAMPLE_FACTOR.mdx +3 -0
  20. package/api-docs/variables/EDGE_BLUR_AMOUNT.mdx +1 -1
  21. package/api-docs/variables/EXCLUDE_BYSTANDERS.mdx +3 -0
  22. package/api-docs/variables/FOREGROUND_THRESHOLD.mdx +1 -1
  23. package/api-docs/variables/LIGHT_WRAP_BLUR_AMOUNT.mdx +3 -0
  24. package/api-docs/variables/LIGHT_WRAP_EDGE_BAND.mdx +3 -0
  25. package/api-docs/variables/LIGHT_WRAP_INTENSITY.mdx +3 -0
  26. package/api-docs/variables/LIGHT_WRAP_TIGHTNESS.mdx +3 -0
  27. package/api-docs/variables/MASK_COMBINE_RATIO.mdx +1 -1
  28. package/api-docs/variables/MORPH_DILATE_RADIUS_PX.mdx +3 -0
  29. package/api-docs/variables/MORPH_ERODE_RADIUS_PX.mdx +3 -0
  30. package/api-docs/variables/MORPH_PASS.mdx +3 -0
  31. package/api-docs/variables/PERSON_CENTER.mdx +3 -0
  32. package/api-docs/variables/SIGMA_RANGE.mdx +3 -0
  33. package/api-docs/variables/SIGMA_SPACE.mdx +3 -0
  34. package/api-docs/variables/STRONG_EDGE_BLUR_AMOUNT.mdx +3 -0
  35. package/api-docs/variables/getCanvasRenderingContext2D.mdx +14 -0
  36. package/api-docs/variables/getImageSize.mdx +13 -0
  37. package/dist/common/backends/webgl/binaryMask.d.ts +8 -0
  38. package/dist/common/backends/webgl/binaryMask.js +95 -0
  39. package/dist/common/backends/webgl/blender.d.ts +2 -1
  40. package/dist/common/backends/webgl/blender.js +18 -15
  41. package/dist/common/backends/webgl/blur.d.ts +1 -1
  42. package/dist/common/backends/webgl/blur.js +23 -16
  43. package/dist/common/backends/webgl/canvas.js +9 -4
  44. package/dist/common/backends/webgl/diffAbsMask.d.ts +10 -0
  45. package/dist/common/backends/webgl/diffAbsMask.js +103 -0
  46. package/dist/common/backends/webgl/geodesicReconstruction.d.ts +13 -0
  47. package/dist/common/backends/webgl/geodesicReconstruction.js +176 -0
  48. package/dist/common/backends/webgl/jointBilateralFilter.d.ts +12 -0
  49. package/dist/common/backends/webgl/jointBilateralFilter.js +108 -0
  50. package/dist/common/backends/webgl/morphErode.d.ts +13 -0
  51. package/dist/common/backends/webgl/morphErode.js +121 -0
  52. package/dist/common/backends/webgl/renderer.js +194 -34
  53. package/dist/common/backends/webgl/replace.d.ts +17 -0
  54. package/dist/common/backends/webgl/replace.js +126 -0
  55. package/dist/common/backends/webgl/selectComponent.d.ts +15 -0
  56. package/dist/common/backends/webgl/selectComponent.js +102 -0
  57. package/dist/common/backends/webgl/smoothingMask.d.ts +3 -3
  58. package/dist/common/backends/webgl/smoothingMask.js +22 -21
  59. package/dist/common/backends/webgl/tentBlur.d.ts +9 -0
  60. package/dist/common/backends/webgl/tentBlur.js +118 -0
  61. package/dist/common/backends/webgl/texture.d.ts +1 -1
  62. package/dist/common/backends/webgl/texture.js +19 -17
  63. package/dist/common/backends/webgl/textureToTexture.d.ts +1 -1
  64. package/dist/common/backends/webgl/textureToTexture.js +19 -16
  65. package/dist/common/backends/webgl/webglUtils.d.ts +7 -1
  66. package/dist/common/backends/webgl/webglUtils.js +64 -6
  67. package/dist/common/backends/webgpu/blender.d.ts +6 -1
  68. package/dist/common/backends/webgpu/blender.js +96 -51
  69. package/dist/common/backends/webgpu/constants.js +1 -1
  70. package/dist/common/backends/webgpu/dualFilterBlur.d.ts +2 -3
  71. package/dist/common/backends/webgpu/dualFilterBlur.js +146 -140
  72. package/dist/common/backends/webgpu/jointBilateralFilter.d.ts +7 -0
  73. package/dist/common/backends/webgpu/jointBilateralFilter.js +162 -0
  74. package/dist/common/backends/webgpu/renderer.js +211 -39
  75. package/dist/common/backends/webgpu/replace.d.ts +11 -0
  76. package/dist/common/backends/webgpu/replace.js +175 -0
  77. package/dist/common/backends/webgpu/resize.d.ts +4 -0
  78. package/dist/common/backends/webgpu/resize.js +76 -0
  79. package/dist/common/backends/webgpu/smoothingMask.d.ts +2 -2
  80. package/dist/common/backends/webgpu/smoothingMask.js +74 -40
  81. package/dist/common/backends/webgpu/tentBlur.d.ts +5 -0
  82. package/dist/common/backends/webgpu/tentBlur.js +131 -0
  83. package/dist/common/backends/webgpu/texture.d.ts +2 -2
  84. package/dist/common/backends/webgpu/texture.js +24 -19
  85. package/dist/common/backends/webgpu/textureToTexture.d.ts +1 -1
  86. package/dist/common/backends/webgpu/textureToTexture.js +28 -15
  87. package/dist/common/backends/webgpu/types.d.ts +2 -0
  88. package/dist/common/backends/webgpu/webgpuUtils.d.ts +24 -4
  89. package/dist/common/backends/webgpu/webgpuUtils.js +60 -11
  90. package/dist/common/constants.d.ts +19 -5
  91. package/dist/common/constants.js +19 -5
  92. package/dist/common/index.d.ts +1 -0
  93. package/dist/common/index.js +1 -0
  94. package/dist/common/tsconfig.tsbuildinfo +1 -1
  95. package/dist/common/types/render.d.ts +142 -13
  96. package/dist/common/types/utils.d.ts +21 -0
  97. package/dist/common/utils.d.ts +16 -0
  98. package/dist/common/utils.js +152 -0
  99. package/dist/main/benchUtils.d.ts +33 -1
  100. package/dist/main/benchUtils.js +145 -11
  101. package/dist/main/tsconfig.tsbuildinfo +1 -1
  102. package/dist/main/video/canvasTransform.d.ts +1 -1
  103. package/dist/main/video/canvasTransform.js +135 -47
  104. package/dist/main/video/index.d.ts +1 -1
  105. package/dist/main/video/index.js +1 -1
  106. package/dist/workers/mediaWorker.js +35 -162
  107. package/dist/workers/tsconfig.tsbuildinfo +1 -1
  108. package/package.json +8 -7
  109. package/dist/common/backends/webgl/shaders/blendFragmentShader.d.ts +0 -1
  110. package/dist/common/backends/webgl/shaders/blendFragmentShader.js +0 -21
  111. package/dist/common/backends/webgl/shaders/dualFilterBlurFragmentShader.d.ts +0 -1
  112. package/dist/common/backends/webgl/shaders/dualFilterBlurFragmentShader.js +0 -45
  113. package/dist/common/backends/webgl/shaders/smoothingMaskFragmentShader.d.ts +0 -1
  114. package/dist/common/backends/webgl/shaders/smoothingMaskFragmentShader.js +0 -57
  115. package/dist/common/backends/webgl/shaders/textureFragmentShader.d.ts +0 -1
  116. package/dist/common/backends/webgl/shaders/textureFragmentShader.js +0 -16
  117. package/dist/common/backends/webgl/shaders/vertexShader.d.ts +0 -1
  118. package/dist/common/backends/webgl/shaders/vertexShader.js +0 -19
@@ -0,0 +1,8 @@
1
+ import type { TextureInfo } from './types';
2
+ /**
3
+ * Create a binary mask renderer based on the provided threshold
4
+ */
5
+ export declare const createBinaryMaskRenderer: (processor: OffscreenCanvas, width: number, height: number) => {
6
+ render: (mask: TextureInfo, threshold: number) => TextureInfo;
7
+ release: () => void;
8
+ };
@@ -0,0 +1,95 @@
1
+ import { assert } from '@pexip/utils';
2
+ import { m3 } from '../../m3';
3
+ import { RENDERING_EVENTS } from '../../constants';
4
+ import { createGLProgram, createMaskTexture, createFrameBuffer, } from './webglUtils';
5
+ import vertexSrc from './shaders/matrix.vert';
6
+ import fragmentSrc from './shaders/binaryMask.frag';
7
+ /**
8
+ * Create a binary mask renderer based on the provided threshold
9
+ */
10
+ export const createBinaryMaskRenderer = (processor, width, height) => {
11
+ const { gl, program, attribLocations, uniformLocations, floatFullChannelSupported, floatSingleChannelSupported, release, } = createGLProgram(processor, {
12
+ attribs: {
13
+ position: 'a_position',
14
+ texCoord: 'a_texCoord',
15
+ },
16
+ uniforms: {
17
+ matrix: 'u_matrix',
18
+ mask: 'u_mask',
19
+ size: 'u_size',
20
+ threshold: 'u_threshold',
21
+ },
22
+ vertexSrc,
23
+ fragmentSrc,
24
+ });
25
+ const vao = gl.createVertexArray();
26
+ gl.bindVertexArray(vao);
27
+ // Position
28
+ const positionBuffer = gl.createBuffer();
29
+ gl.enableVertexAttribArray(attribLocations.position);
30
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
31
+ gl.vertexAttribPointer(attribLocations.position, 2, gl.FLOAT, false, 0, 0);
32
+ gl.bufferData(gl.ARRAY_BUFFER,
33
+ // prettier-ignore
34
+ new Float32Array([
35
+ 0, 0,
36
+ 0, 1,
37
+ 1, 0,
38
+ 1, 0,
39
+ 0, 1,
40
+ 1, 1,
41
+ ]), gl.STATIC_DRAW);
42
+ // Texture coordinates for the rectangle
43
+ const texCoordBuffer = gl.createBuffer();
44
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
45
+ gl.bufferData(gl.ARRAY_BUFFER,
46
+ // prettier-ignore
47
+ new Float32Array([
48
+ 0, 0,
49
+ 0, 1,
50
+ 1, 0,
51
+ 1, 0,
52
+ 0, 1,
53
+ 1, 1,
54
+ ]), gl.STATIC_DRAW);
55
+ gl.enableVertexAttribArray(attribLocations.texCoord);
56
+ gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
57
+ const outputTexture = createMaskTexture(gl, width, height, false, floatSingleChannelSupported, floatFullChannelSupported);
58
+ const frameBuffer = createFrameBuffer(gl, outputTexture);
59
+ return {
60
+ render: (mask, threshold) => {
61
+ assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
62
+ gl.clearColor(0, 0, 0, 0);
63
+ gl.clear(gl.COLOR_BUFFER_BIT);
64
+ gl.useProgram(program);
65
+ gl.bindVertexArray(vao);
66
+ gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
67
+ gl.viewport(0, 0, width, height);
68
+ // Textures
69
+ gl.activeTexture(gl.TEXTURE0);
70
+ gl.uniform1i(uniformLocations.mask, 0);
71
+ gl.bindTexture(gl.TEXTURE_2D, mask.texture);
72
+ gl.uniform2i(uniformLocations.size, mask.width, mask.height);
73
+ gl.uniform1f(uniformLocations.threshold, threshold);
74
+ // No Flip Y Coordinate for drawing on the frame buffer
75
+ // Project, position and scale to full-size of the canvas
76
+ const matrix = m3.projection(1, 1, 1);
77
+ gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
78
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
79
+ // Cleanup
80
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
81
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
82
+ gl.bindTexture(gl.TEXTURE_2D, null);
83
+ gl.bindVertexArray(null);
84
+ return { texture: outputTexture, width, height };
85
+ },
86
+ release: () => {
87
+ gl.deleteBuffer(positionBuffer);
88
+ gl.deleteBuffer(texCoordBuffer);
89
+ gl.deleteTexture(outputTexture);
90
+ gl.deleteFramebuffer(frameBuffer);
91
+ gl.deleteVertexArray(vao);
92
+ release();
93
+ },
94
+ };
95
+ };
@@ -1,3 +1,4 @@
1
+ import type { RendererOptions } from '../../types/render';
1
2
  import type { TextureInfo } from './types';
2
3
  /**
3
4
  * Blend foreground and background according to the mask
@@ -7,6 +8,6 @@ export declare const createBlendRenderer: (processor: OffscreenCanvas) => {
7
8
  mask: TextureInfo;
8
9
  foreground: TextureInfo;
9
10
  background: TextureInfo;
10
- }) => TextureInfo;
11
+ }, options: RendererOptions) => TextureInfo;
11
12
  release: () => void;
12
13
  };
@@ -1,26 +1,27 @@
1
1
  import { assert } from '@pexip/utils';
2
2
  import { RENDERING_EVENTS } from '../../constants';
3
3
  import { m3 } from '../../m3';
4
- import { createGLProgram, createAndSetupTexture } from './webglUtils';
5
- import { vertexShaderSource } from './shaders/vertexShader';
6
- import { blendFragmentShaderSource } from './shaders/blendFragmentShader';
4
+ import { createFrameBuffer, createGLProgram, createRGBAFrameTexture, } from './webglUtils';
5
+ import vertexSrc from './shaders/matrix.vert';
6
+ import fragmentSrc from './shaders/blend.frag';
7
7
  /**
8
8
  * Blend foreground and background according to the mask
9
9
  */
10
10
  export const createBlendRenderer = (processor) => {
11
- const { gl, program, attribLocations, uniformLocations, release } = createGLProgram(processor, {
11
+ const { gl, program, attribLocations, floatFullChannelSupported, uniformLocations, release, } = createGLProgram(processor, {
12
12
  attribs: {
13
13
  position: 'a_position',
14
14
  texCoord: 'a_texCoord',
15
15
  },
16
16
  uniforms: {
17
17
  matrix: 'u_matrix',
18
+ mask: 'u_mask',
18
19
  frameBackground: 'u_frame_background',
19
20
  frameForeground: 'u_frame_foreground',
20
- mask: 'u_mask',
21
+ confidenceThresholds: 'u_confidence_thresholds',
21
22
  },
22
- vertexSrc: vertexShaderSource,
23
- fragmentSrc: blendFragmentShaderSource,
23
+ vertexSrc,
24
+ fragmentSrc,
24
25
  });
25
26
  gl.enable(gl.BLEND);
26
27
  const vao = gl.createVertexArray();
@@ -55,18 +56,16 @@ export const createBlendRenderer = (processor) => {
55
56
  ]), gl.STATIC_DRAW);
56
57
  gl.enableVertexAttribArray(attribLocations.texCoord);
57
58
  gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
58
- const outputTexture = createAndSetupTexture(gl);
59
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, processor.width, processor.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
60
- const frameBuffer = gl.createFramebuffer();
61
- gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
62
- gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, outputTexture, 0);
59
+ const outputTexture = createRGBAFrameTexture(gl, processor.width, processor.height, true, floatFullChannelSupported);
60
+ const frameBuffer = createFrameBuffer(gl, outputTexture);
63
61
  return {
64
- render: ({ mask, foreground, background, }) => {
62
+ render: ({ mask, foreground, background, }, options) => {
65
63
  assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
64
+ gl.useProgram(program);
66
65
  gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
67
66
  gl.viewport(0, 0, processor.width, processor.height);
68
- gl.useProgram(program);
69
67
  gl.bindVertexArray(vao);
68
+ gl.uniform2f(uniformLocations.confidenceThresholds, options.backgroundThreshold, options.foregroundThreshold);
70
69
  // Textures
71
70
  gl.activeTexture(gl.TEXTURE0);
72
71
  gl.uniform1i(uniformLocations.frameForeground, 0);
@@ -82,7 +81,11 @@ export const createBlendRenderer = (processor) => {
82
81
  const matrix = m3.projection(1, 1, 1);
83
82
  gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
84
83
  gl.drawArrays(gl.TRIANGLES, 0, 6);
85
- assert(outputTexture);
84
+ // Cleanup
85
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
86
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
87
+ gl.bindTexture(gl.TEXTURE_2D, null);
88
+ gl.bindVertexArray(null);
86
89
  return {
87
90
  texture: outputTexture,
88
91
  width: processor.width,
@@ -2,7 +2,7 @@ import type { TextureInfo } from './types';
2
2
  /**
3
3
  * Blur provided frame
4
4
  */
5
- export declare const createBlurRenderer: (processor: OffscreenCanvas, pass: number) => {
5
+ export declare const createBlurRenderer: (processor: OffscreenCanvas, pass: number, redOnly?: boolean) => {
6
6
  render: (frame: TextureInfo, pass: number) => TextureInfo;
7
7
  release: () => void;
8
8
  };
@@ -2,15 +2,15 @@ import { assert } from '@pexip/utils';
2
2
  import { clamping } from '../../utils';
3
3
  import { RENDERING_EVENTS } from '../../constants';
4
4
  import { m3 } from '../../m3';
5
- import { createAndSetupTexture, createGLProgram } from './webglUtils';
6
- import { vertexShaderSource } from './shaders/vertexShader';
7
- import { dualFilterBlurFragmentShaderSource } from './shaders/dualFilterBlurFragmentShader';
5
+ import { createFrameBuffer, createGLProgram, createMaskTexture, createRGBAFrameTexture, } from './webglUtils';
6
+ import vertexSrc from './shaders/matrix.vert';
7
+ import fragmentSrc from './shaders/dualFilterBlur.frag';
8
8
  const clampBlurAmount = clamping(1, 9);
9
9
  /**
10
10
  * Blur provided frame
11
11
  */
12
- export const createBlurRenderer = (processor, pass) => {
13
- const { gl, program, attribLocations, uniformLocations, release } = createGLProgram(processor, {
12
+ export const createBlurRenderer = (processor, pass, redOnly = false) => {
13
+ const { gl, program, attribLocations, uniformLocations, floatSingleChannelSupported, floatFullChannelSupported, release, } = createGLProgram(processor, {
14
14
  attribs: {
15
15
  position: 'a_position',
16
16
  texCoord: 'a_texCoord',
@@ -20,8 +20,8 @@ export const createBlurRenderer = (processor, pass) => {
20
20
  downsampling: 'u_downsampling',
21
21
  frame: 'u_frame',
22
22
  },
23
- vertexSrc: vertexShaderSource,
24
- fragmentSrc: dualFilterBlurFragmentShaderSource,
23
+ vertexSrc,
24
+ fragmentSrc,
25
25
  });
26
26
  const vao = gl.createVertexArray();
27
27
  gl.bindVertexArray(vao);
@@ -61,18 +61,13 @@ export const createBlurRenderer = (processor, pass) => {
61
61
  gl.viewport(0, 0, width, height);
62
62
  };
63
63
  const createFramebufferAndTexture = (idx) => {
64
- const texture = createAndSetupTexture(gl);
65
- assert(texture);
66
64
  // Avoid fractional value
67
65
  const width = Math.trunc(processor.width / 2 ** idx);
68
66
  const height = Math.trunc(processor.height / 2 ** idx);
69
- gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
70
- const frameBuffer = gl.createFramebuffer();
71
- assert(frameBuffer);
72
- gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
73
- // Attach a texture to it.
74
- const attachmentPoint = gl.COLOR_ATTACHMENT0;
75
- gl.framebufferTexture2D(gl.FRAMEBUFFER, attachmentPoint, gl.TEXTURE_2D, texture, 0);
67
+ const texture = redOnly
68
+ ? createMaskTexture(gl, width, height, true, floatSingleChannelSupported, floatFullChannelSupported)
69
+ : createRGBAFrameTexture(gl, width, height, true, floatFullChannelSupported);
70
+ const frameBuffer = createFrameBuffer(gl, texture);
76
71
  return { texture, frameBuffer, width, height };
77
72
  };
78
73
  const generateBlurBuffers = (pass, offset = 0) => {
@@ -87,6 +82,13 @@ export const createBlurRenderer = (processor, pass) => {
87
82
  return {
88
83
  render: (frame, pass) => {
89
84
  assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
85
+ if (!pass) {
86
+ return {
87
+ texture: frame.texture,
88
+ width: frame.width,
89
+ height: frame.height,
90
+ };
91
+ }
90
92
  gl.useProgram(program);
91
93
  gl.bindVertexArray(vao);
92
94
  // Frame texture
@@ -153,6 +155,11 @@ export const createBlurRenderer = (processor, pass) => {
153
155
  // for the next draw, use the texture we just rendered to.
154
156
  gl.bindTexture(gl.TEXTURE_2D, texture);
155
157
  }
158
+ // Cleanup
159
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
160
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
161
+ gl.bindTexture(gl.TEXTURE_2D, null);
162
+ gl.bindVertexArray(null);
156
163
  return {
157
164
  texture: blurBuffers[0]?.texture ?? frame.texture,
158
165
  width: blurBuffers[0]?.width ?? frame.width,
@@ -2,8 +2,8 @@ import { assert } from '@pexip/utils';
2
2
  import { m3 } from '../../m3';
3
3
  import { RENDERING_EVENTS } from '../../constants';
4
4
  import { createGLProgram } from './webglUtils';
5
- import { vertexShaderSource } from './shaders/vertexShader';
6
- import { textureFragmentShaderSource } from './shaders/textureFragmentShader';
5
+ import vertexSrc from './shaders/matrix.vert';
6
+ import fragmentSrc from './shaders/texture.frag';
7
7
  /**
8
8
  * Render texture to the processing canvas framebuffer
9
9
  */
@@ -17,8 +17,8 @@ export const createCanvasRenderer = (processor) => {
17
17
  matrix: 'u_matrix',
18
18
  texture: 'u_texture',
19
19
  },
20
- vertexSrc: vertexShaderSource,
21
- fragmentSrc: textureFragmentShaderSource,
20
+ vertexSrc,
21
+ fragmentSrc,
22
22
  });
23
23
  const vao = gl.createVertexArray();
24
24
  gl.bindVertexArray(vao);
@@ -72,6 +72,11 @@ export const createCanvasRenderer = (processor) => {
72
72
  gl.activeTexture(gl.TEXTURE0);
73
73
  gl.bindTexture(gl.TEXTURE_2D, texture.texture);
74
74
  gl.drawArrays(gl.TRIANGLES, 0, 6);
75
+ // Cleanup
76
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
77
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
78
+ gl.bindTexture(gl.TEXTURE_2D, null);
79
+ gl.bindVertexArray(null);
75
80
  },
76
81
  release: () => {
77
82
  gl.deleteBuffer(positionBuffer);
@@ -0,0 +1,10 @@
1
+ import type { TextureInfo } from './types';
2
+ /**
3
+ * Create absulute difference renderer to caculate the difference between 2 textures
4
+ */
5
+ export declare const createDiffAbsRenderer: (processor: OffscreenCanvas, width: number, height: number) => {
6
+ render: (textureA: TextureInfo, textureB: TextureInfo) => TextureInfo & {
7
+ frameBuffer: WebGLFramebuffer;
8
+ };
9
+ release: () => void;
10
+ };
@@ -0,0 +1,103 @@
1
+ import { assert } from '@pexip/utils';
2
+ import { m3 } from '../../m3';
3
+ import { RENDERING_EVENTS } from '../../constants';
4
+ import { createGLProgram, createMaskTexture, createFrameBuffer, } from './webglUtils';
5
+ import vertexSrc from './shaders/matrix.vert';
6
+ import fragmentSrc from './shaders/diffAbs.frag';
7
+ /**
8
+ * Create absulute difference renderer to caculate the difference between 2 textures
9
+ */
10
+ export const createDiffAbsRenderer = (processor, width, height) => {
11
+ const { gl, program, attribLocations, uniformLocations, floatSingleChannelSupported, floatFullChannelSupported, release, } = createGLProgram(processor, {
12
+ attribs: {
13
+ position: 'a_position',
14
+ texCoord: 'a_texCoord',
15
+ },
16
+ uniforms: {
17
+ matrix: 'u_matrix',
18
+ texA: 'u_tex_a',
19
+ texB: 'u_tex_b',
20
+ size: 'u_size',
21
+ },
22
+ vertexSrc,
23
+ fragmentSrc,
24
+ });
25
+ const vao = gl.createVertexArray();
26
+ gl.bindVertexArray(vao);
27
+ // Position
28
+ const positionBuffer = gl.createBuffer();
29
+ gl.enableVertexAttribArray(attribLocations.position);
30
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
31
+ gl.vertexAttribPointer(attribLocations.position, 2, gl.FLOAT, false, 0, 0);
32
+ gl.bufferData(gl.ARRAY_BUFFER,
33
+ // prettier-ignore
34
+ new Float32Array([
35
+ 0, 0,
36
+ 0, 1,
37
+ 1, 0,
38
+ 1, 0,
39
+ 0, 1,
40
+ 1, 1,
41
+ ]), gl.STATIC_DRAW);
42
+ // Texture coordinates for the rectangle
43
+ const texCoordBuffer = gl.createBuffer();
44
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
45
+ gl.bufferData(gl.ARRAY_BUFFER,
46
+ // prettier-ignore
47
+ new Float32Array([
48
+ 0, 0,
49
+ 0, 1,
50
+ 1, 0,
51
+ 1, 0,
52
+ 0, 1,
53
+ 1, 1,
54
+ ]), gl.STATIC_DRAW);
55
+ gl.enableVertexAttribArray(attribLocations.texCoord);
56
+ gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
57
+ const outputTexturePing = createMaskTexture(gl, width, height, true, floatSingleChannelSupported, floatFullChannelSupported);
58
+ const frameBufferPing = createFrameBuffer(gl, outputTexturePing);
59
+ return {
60
+ render: (textureA, textureB) => {
61
+ assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
62
+ assert(textureA.width === textureB.width &&
63
+ textureA.height === textureB.height);
64
+ gl.useProgram(program);
65
+ gl.bindVertexArray(vao);
66
+ gl.uniform2i(uniformLocations.size, textureA.width, textureA.height);
67
+ gl.activeTexture(gl.TEXTURE0);
68
+ gl.uniform1i(uniformLocations.texA, 0);
69
+ gl.bindTexture(gl.TEXTURE_2D, textureA.texture);
70
+ gl.activeTexture(gl.TEXTURE1);
71
+ gl.uniform1i(uniformLocations.texB, 1);
72
+ gl.bindTexture(gl.TEXTURE_2D, textureB.texture);
73
+ // No Flip Y Coordinate for drawing on the frame buffer
74
+ // Project, position and scale to full-size of the canvas
75
+ const matrix = m3.projection(1, 1, 1);
76
+ gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
77
+ gl.bindFramebuffer(gl.FRAMEBUFFER, frameBufferPing);
78
+ gl.viewport(0, 0, width, height);
79
+ gl.clearColor(0, 0, 0, 0);
80
+ gl.clear(gl.COLOR_BUFFER_BIT);
81
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
82
+ // Cleanup
83
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
84
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
85
+ gl.bindTexture(gl.TEXTURE_2D, null);
86
+ gl.bindVertexArray(null);
87
+ return {
88
+ texture: outputTexturePing,
89
+ frameBuffer: frameBufferPing,
90
+ width,
91
+ height,
92
+ };
93
+ },
94
+ release: () => {
95
+ gl.deleteBuffer(positionBuffer);
96
+ gl.deleteBuffer(texCoordBuffer);
97
+ gl.deleteTexture(outputTexturePing);
98
+ gl.deleteFramebuffer(frameBufferPing);
99
+ gl.deleteVertexArray(vao);
100
+ release();
101
+ },
102
+ };
103
+ };
@@ -0,0 +1,13 @@
1
+ import type { RendererOptions } from '../../types/render';
2
+ import type { TextureInfo } from './types';
3
+ /**
4
+ * A Geodesic Reconstruction Renderer that performs geodesic dilation of
5
+ * a mask constrained by a reference mask.
6
+ */
7
+ export declare const createGeodesicReconstructionRenderer: (processor: OffscreenCanvas, width: number, height: number) => {
8
+ render: ({ mask, maskRef }: {
9
+ mask: TextureInfo;
10
+ maskRef: TextureInfo;
11
+ }, options: Pick<RendererOptions, "morphDilateRadiusPx" | "morphPass">) => TextureInfo;
12
+ release: () => void;
13
+ };
@@ -0,0 +1,176 @@
1
+ import { assert } from '@pexip/utils';
2
+ import { m3 } from '../../m3';
3
+ import { RENDERING_EVENTS } from '../../constants';
4
+ import { clamping } from '../../utils';
5
+ import { createGLProgram, createMaskTexture, createFrameBuffer, } from './webglUtils';
6
+ import vertexSrc from './shaders/matrix.vert';
7
+ import fragmentSrc from './shaders/dilateClipToMask.frag';
8
+ import { createDiffAbsRenderer } from './diffAbsMask';
9
+ // Convergence threshold used when testing for geodesic reconstruction stability.
10
+ const CONVERGENCE_MAX_ITERATIONS = 64;
11
+ const MAX_RADIUS_PX = 64;
12
+ const clampRadiusPx = clamping(0, MAX_RADIUS_PX);
13
+ /**
14
+ * A Geodesic Reconstruction Renderer that performs geodesic dilation of
15
+ * a mask constrained by a reference mask.
16
+ */
17
+ export const createGeodesicReconstructionRenderer = (processor, width, height) => {
18
+ const { gl, program, attribLocations, uniformLocations, floatSingleChannelSupported, floatFullChannelSupported, release, } = createGLProgram(processor, {
19
+ attribs: {
20
+ position: 'a_position',
21
+ texCoord: 'a_texCoord',
22
+ },
23
+ uniforms: {
24
+ matrix: 'u_matrix',
25
+ mask: 'u_mask',
26
+ maskRef: 'u_ref_mask',
27
+ texelSize: 'u_texel_size',
28
+ radiusPx: 'u_radius_px',
29
+ direction: 'u_direction',
30
+ },
31
+ vertexSrc,
32
+ fragmentSrc,
33
+ });
34
+ const vao = gl.createVertexArray();
35
+ gl.bindVertexArray(vao);
36
+ // Position
37
+ const positionBuffer = gl.createBuffer();
38
+ gl.enableVertexAttribArray(attribLocations.position);
39
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
40
+ gl.vertexAttribPointer(attribLocations.position, 2, gl.FLOAT, false, 0, 0);
41
+ gl.bufferData(gl.ARRAY_BUFFER,
42
+ // prettier-ignore
43
+ new Float32Array([
44
+ 0, 0,
45
+ 0, 1,
46
+ 1, 0,
47
+ 1, 0,
48
+ 0, 1,
49
+ 1, 1,
50
+ ]), gl.STATIC_DRAW);
51
+ // Texture coordinates for the rectangle
52
+ const texCoordBuffer = gl.createBuffer();
53
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
54
+ gl.bufferData(gl.ARRAY_BUFFER,
55
+ // prettier-ignore
56
+ new Float32Array([
57
+ 0, 0,
58
+ 0, 1,
59
+ 1, 0,
60
+ 1, 0,
61
+ 0, 1,
62
+ 1, 1,
63
+ ]), gl.STATIC_DRAW);
64
+ gl.enableVertexAttribArray(attribLocations.texCoord);
65
+ gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
66
+ const scaleFactor = processor.width / width;
67
+ const MIN_CCL_WIDTH = 32;
68
+ const MIN_CCL_HEIGHT = 18;
69
+ const convergenceWidth = Math.max(Math.floor(width / 4), MIN_CCL_WIDTH);
70
+ const convergenceHeight = Math.max(Math.floor(height / 4), MIN_CCL_HEIGHT);
71
+ const CONVERGENCE_EPSILON = convergenceWidth === MIN_CCL_WIDTH ? 1e-8 : 1e-4;
72
+ const convergenceSize = convergenceWidth * convergenceHeight;
73
+ const diffRenderer = createDiffAbsRenderer(processor, convergenceWidth, convergenceHeight);
74
+ const supportFloat = floatSingleChannelSupported || floatFullChannelSupported;
75
+ const readPixelsFormat = supportFloat ? gl.RGBA : gl.RED;
76
+ const readPixelsType = supportFloat ? gl.FLOAT : gl.UNSIGNED_BYTE;
77
+ const convergenceDiff = supportFloat
78
+ ? new Float32Array(convergenceSize * 4)
79
+ : new Uint8Array(convergenceSize);
80
+ const outputTexturePing = createMaskTexture(gl, width, height, false, floatSingleChannelSupported, floatFullChannelSupported);
81
+ const outputTexturePong = createMaskTexture(gl, width, height, false, floatSingleChannelSupported, floatFullChannelSupported);
82
+ const frameBufferPing = createFrameBuffer(gl, outputTexturePing);
83
+ const frameBufferPong = createFrameBuffer(gl, outputTexturePong);
84
+ return {
85
+ render: ({ mask, maskRef }, options) => {
86
+ assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
87
+ let write = frameBufferPing;
88
+ let read = mask.texture;
89
+ const dilate = () => {
90
+ gl.useProgram(program);
91
+ gl.bindVertexArray(vao);
92
+ gl.uniform1i(uniformLocations.radiusPx, clampRadiusPx(Math.floor(options.morphDilateRadiusPx / scaleFactor)));
93
+ gl.uniform2f(uniformLocations.texelSize, 1 / mask.width, 1 / mask.height);
94
+ // Reference Mask
95
+ gl.activeTexture(gl.TEXTURE1);
96
+ gl.uniform1i(uniformLocations.maskRef, 1);
97
+ gl.bindTexture(gl.TEXTURE_2D, maskRef.texture);
98
+ // No Flip Y Coordinate for drawing on the frame buffer
99
+ // Project, position and scale to full-size of the canvas
100
+ const matrix = m3.projection(1, 1, 1);
101
+ gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
102
+ // Separable
103
+ for (let j = 0; j < 2; j++) {
104
+ // Textures
105
+ gl.activeTexture(gl.TEXTURE0);
106
+ gl.uniform1i(uniformLocations.mask, 0);
107
+ gl.bindTexture(gl.TEXTURE_2D, read);
108
+ // Horizontal then Vertical
109
+ gl.uniform2f(uniformLocations.direction, 1.0 - j, 0.0 + j);
110
+ gl.bindFramebuffer(gl.FRAMEBUFFER, write);
111
+ gl.viewport(0, 0, width, height);
112
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
113
+ // Swap
114
+ [read, write] =
115
+ write === frameBufferPing
116
+ ? [outputTexturePing, frameBufferPong]
117
+ : [outputTexturePong, frameBufferPing];
118
+ }
119
+ };
120
+ for (let i = 0; i < options.morphPass; i++) {
121
+ dilate();
122
+ }
123
+ let convergent = false;
124
+ let count = 0;
125
+ while (!convergent) {
126
+ dilate();
127
+ const diff = diffRenderer.render({ texture: outputTexturePing, width, height }, { texture: outputTexturePong, width, height });
128
+ gl.bindFramebuffer(gl.FRAMEBUFFER, diff.frameBuffer);
129
+ gl.readPixels(0, 0, convergenceWidth, convergenceHeight, readPixelsFormat, readPixelsType, convergenceDiff);
130
+ let sum = 0;
131
+ let meanDiff = 0;
132
+ if (supportFloat) {
133
+ for (let i = 0, j = 0; i < convergenceSize; ++i, j += 4) {
134
+ //@ts-expect-error will not be undefined
135
+ sum += convergenceDiff[j];
136
+ }
137
+ meanDiff = sum / convergenceSize;
138
+ }
139
+ else {
140
+ for (let i = 0; i < convergenceSize; ++i) {
141
+ //@ts-expect-error will not be undefined
142
+ sum += convergenceDiff[i];
143
+ }
144
+ meanDiff = sum / convergenceSize / 255.0;
145
+ }
146
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
147
+ if (meanDiff < CONVERGENCE_EPSILON ||
148
+ count >= CONVERGENCE_MAX_ITERATIONS) {
149
+ // console.log(
150
+ // `Geodesic reconstruction converged in ${count} iterations with ${meanDiff}`,
151
+ // {convergenceWidth, convergenceHeight, width, height},
152
+ // );
153
+ convergent = true;
154
+ }
155
+ count++;
156
+ }
157
+ // Cleanup
158
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
159
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
160
+ gl.bindTexture(gl.TEXTURE_2D, null);
161
+ gl.bindVertexArray(null);
162
+ return { texture: read, width, height };
163
+ },
164
+ release: () => {
165
+ gl.deleteBuffer(positionBuffer);
166
+ gl.deleteBuffer(texCoordBuffer);
167
+ gl.deleteTexture(outputTexturePing);
168
+ gl.deleteTexture(outputTexturePong);
169
+ gl.deleteFramebuffer(frameBufferPing);
170
+ gl.deleteFramebuffer(frameBufferPong);
171
+ gl.deleteVertexArray(vao);
172
+ diffRenderer.release();
173
+ release();
174
+ },
175
+ };
176
+ };
@@ -0,0 +1,12 @@
1
+ import type { RendererOptions } from '../../types/render';
2
+ import type { TextureInfo } from './types';
3
+ /**
4
+ * Joint Bilateral Filter
5
+ */
6
+ export declare const createJointBilateralFilterRenderer: (processor: OffscreenCanvas, width: number, height: number) => {
7
+ render: ({ input, guide }: {
8
+ input: TextureInfo;
9
+ guide: TextureInfo;
10
+ }, options: RendererOptions) => TextureInfo;
11
+ release: () => void;
12
+ };