@livekit/track-processors 0.5.4 → 0.5.5

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/dist/index.mjs CHANGED
@@ -264,6 +264,28 @@ function initTexture(gl, texIndex) {
264
264
  gl.bindTexture(gl.TEXTURE_2D, texture);
265
265
  return texture;
266
266
  }
267
+ function createShader(gl, type, source) {
268
+ const shader = gl.createShader(type);
269
+ gl.shaderSource(shader, source);
270
+ gl.compileShader(shader);
271
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
272
+ console.error("Shader compile failed:", gl.getShaderInfoLog(shader));
273
+ gl.deleteShader(shader);
274
+ throw new Error("Shader compile failed");
275
+ }
276
+ return shader;
277
+ }
278
+ function createProgram(gl, vs, fs) {
279
+ const program = gl.createProgram();
280
+ gl.attachShader(program, vs);
281
+ gl.attachShader(program, fs);
282
+ gl.linkProgram(program);
283
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
284
+ console.error("Program link failed:", gl.getProgramInfoLog(program));
285
+ throw new Error("Program link failed");
286
+ }
287
+ return program;
288
+ }
267
289
  function createFramebuffer(gl, texture, width, height) {
268
290
  const framebuffer = gl.createFramebuffer();
269
291
  gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
@@ -328,7 +350,7 @@ var vertexShaderSource = (flipY = true) => `#version 300 es
328
350
 
329
351
  // src/webgl/shader-programs/blurShader.ts
330
352
  var blurFragmentShader = glsl`#version 300 es
331
- precision highp float;
353
+ precision mediump float;
332
354
  in vec2 texCoords;
333
355
  uniform sampler2D u_texture;
334
356
  uniform vec2 u_texelSize;
@@ -357,33 +379,9 @@ var blurFragmentShader = glsl`#version 300 es
357
379
  }
358
380
  `;
359
381
  function createBlurProgram(gl) {
360
- const blurFrag = gl.createShader(gl.FRAGMENT_SHADER);
361
- if (!blurFrag) {
362
- throw Error("cannot create blur shader");
363
- }
364
- gl.shaderSource(blurFrag, blurFragmentShader);
365
- gl.compileShader(blurFrag);
366
- if (!gl.getShaderParameter(blurFrag, gl.COMPILE_STATUS)) {
367
- const info = gl.getShaderInfoLog(blurFrag);
368
- throw Error(`Failed to compile blur shader: ${info}`);
369
- }
370
- const blurVertexShader = gl.createShader(gl.VERTEX_SHADER);
371
- if (!blurVertexShader) {
372
- throw Error("cannot create blur vertex shader");
373
- }
374
- gl.shaderSource(blurVertexShader, vertexShaderSource());
375
- gl.compileShader(blurVertexShader);
376
- const blurProgram = gl.createProgram();
377
- if (!blurProgram) {
378
- throw Error("cannot create blur program");
379
- }
380
- gl.attachShader(blurProgram, blurVertexShader);
381
- gl.attachShader(blurProgram, blurFrag);
382
- gl.linkProgram(blurProgram);
383
- if (!gl.getProgramParameter(blurProgram, gl.LINK_STATUS)) {
384
- const info = gl.getProgramInfoLog(blurProgram);
385
- throw Error(`Failed to link blur program: ${info}`);
386
- }
382
+ const blurVertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource());
383
+ const blurFrag = createShader(gl, gl.FRAGMENT_SHADER, blurFragmentShader);
384
+ const blurProgram = createProgram(gl, blurVertexShader, blurFrag);
387
385
  const blurUniforms = {
388
386
  position: gl.getAttribLocation(blurProgram, "position"),
389
387
  texture: gl.getUniformLocation(blurProgram, "u_texture"),
@@ -458,37 +456,9 @@ void main() {
458
456
  }
459
457
  `;
460
458
  function createBoxBlurProgram(gl) {
461
- const vertexShader = gl.createShader(gl.VERTEX_SHADER);
462
- if (!vertexShader) {
463
- throw Error("cannot create vertex shader");
464
- }
465
- gl.shaderSource(vertexShader, vertexShaderSource());
466
- gl.compileShader(vertexShader);
467
- if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
468
- const info = gl.getShaderInfoLog(vertexShader);
469
- throw Error(`Failed to compile vertex shader: ${info}`);
470
- }
471
- const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
472
- if (!fragmentShader) {
473
- throw Error("cannot create fragment shader");
474
- }
475
- gl.shaderSource(fragmentShader, boxBlurFragmentShader);
476
- gl.compileShader(fragmentShader);
477
- if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
478
- const info = gl.getShaderInfoLog(fragmentShader);
479
- throw Error(`Failed to compile box blur shader: ${info}`);
480
- }
481
- const program = gl.createProgram();
482
- if (!program) {
483
- throw Error("cannot create box blur program");
484
- }
485
- gl.attachShader(program, vertexShader);
486
- gl.attachShader(program, fragmentShader);
487
- gl.linkProgram(program);
488
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
489
- const info = gl.getProgramInfoLog(program);
490
- throw Error(`Failed to link box blur program: ${info}`);
491
- }
459
+ const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource());
460
+ const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, boxBlurFragmentShader);
461
+ const program = createProgram(gl, vertexShader, fragmentShader);
492
462
  const uniforms = {
493
463
  position: gl.getAttribLocation(program, "position"),
494
464
  texture: gl.getUniformLocation(program, "u_texture"),
@@ -506,7 +476,7 @@ function createBoxBlurProgram(gl) {
506
476
 
507
477
  // src/webgl/shader-programs/compositeShader.ts
508
478
  var compositeFragmentShader = glsl`#version 300 es
509
- precision highp float;
479
+ precision mediump float;
510
480
  in vec2 texCoords;
511
481
  uniform sampler2D background;
512
482
  uniform sampler2D frame;
@@ -536,37 +506,9 @@ var compositeFragmentShader = glsl`#version 300 es
536
506
  }
537
507
  `;
538
508
  function createCompositeProgram(gl) {
539
- const vertexShader = gl.createShader(gl.VERTEX_SHADER);
540
- if (!vertexShader) {
541
- throw Error("cannot create vertex shader");
542
- }
543
- gl.shaderSource(vertexShader, vertexShaderSource());
544
- gl.compileShader(vertexShader);
545
- if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
546
- const info = gl.getShaderInfoLog(vertexShader);
547
- throw Error(`Failed to compile vertex shader: ${info}`);
548
- }
549
- const compositeShader = gl.createShader(gl.FRAGMENT_SHADER);
550
- if (!compositeShader) {
551
- throw Error("cannot create fragment shader");
552
- }
553
- gl.shaderSource(compositeShader, compositeFragmentShader);
554
- gl.compileShader(compositeShader);
555
- if (!gl.getShaderParameter(compositeShader, gl.COMPILE_STATUS)) {
556
- const info = gl.getShaderInfoLog(compositeShader);
557
- throw Error(`Failed to compile composite shader: ${info}`);
558
- }
559
- const compositeProgram = gl.createProgram();
560
- if (!compositeProgram) {
561
- throw Error("cannot create composite program");
562
- }
563
- gl.attachShader(compositeProgram, vertexShader);
564
- gl.attachShader(compositeProgram, compositeShader);
565
- gl.linkProgram(compositeProgram);
566
- if (!gl.getProgramParameter(compositeProgram, gl.LINK_STATUS)) {
567
- const info = gl.getProgramInfoLog(compositeProgram);
568
- throw Error(`Failed to link composite program: ${info}`);
569
- }
509
+ const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource());
510
+ const compositeShader = createShader(gl, gl.FRAGMENT_SHADER, compositeFragmentShader);
511
+ const compositeProgram = createProgram(gl, vertexShader, compositeShader);
570
512
  const attribLocations = {
571
513
  position: gl.getAttribLocation(compositeProgram, "position")
572
514
  };
@@ -585,6 +527,63 @@ function createCompositeProgram(gl) {
585
527
  };
586
528
  }
587
529
 
530
+ // src/webgl/shader-programs/downSampler.ts
531
+ function createDownSampler(gl, width, height) {
532
+ const texture = gl.createTexture();
533
+ gl.bindTexture(gl.TEXTURE_2D, texture);
534
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
535
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
536
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
537
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
538
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
539
+ const framebuffer = gl.createFramebuffer();
540
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
541
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
542
+ const vertexSource = `
543
+ attribute vec2 position;
544
+ varying vec2 v_uv;
545
+ void main() {
546
+ v_uv = (position + 1.0) * 0.5;
547
+ gl_Position = vec4(position, 0.0, 1.0);
548
+ }
549
+ `;
550
+ const fragmentSource = `
551
+ precision mediump float;
552
+ varying vec2 v_uv;
553
+ uniform sampler2D u_texture;
554
+ void main() {
555
+ gl_FragColor = texture2D(u_texture, v_uv);
556
+ }
557
+ `;
558
+ const vertShader = createShader(gl, gl.VERTEX_SHADER, vertexSource);
559
+ const fragShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSource);
560
+ const program = createProgram(gl, vertShader, fragShader);
561
+ const uniforms = {
562
+ texture: gl.getUniformLocation(program, "u_texture"),
563
+ position: gl.getAttribLocation(program, "position")
564
+ };
565
+ return {
566
+ framebuffer,
567
+ texture,
568
+ program,
569
+ uniforms
570
+ };
571
+ }
572
+ function applyDownsampling(gl, inputTexture, downSampler, vertexBuffer, width, height) {
573
+ gl.useProgram(downSampler.program);
574
+ gl.bindFramebuffer(gl.FRAMEBUFFER, downSampler.framebuffer);
575
+ gl.viewport(0, 0, width, height);
576
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
577
+ gl.enableVertexAttribArray(downSampler.uniforms.position);
578
+ gl.vertexAttribPointer(downSampler.uniforms.position, 2, gl.FLOAT, false, 0, 0);
579
+ gl.activeTexture(gl.TEXTURE0);
580
+ gl.bindTexture(gl.TEXTURE_2D, inputTexture);
581
+ gl.uniform1i(downSampler.uniforms.texture, 0);
582
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
583
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
584
+ return downSampler.texture;
585
+ }
586
+
588
587
  // src/webgl/index.ts
589
588
  var setupWebGL = (canvas) => {
590
589
  const gl = canvas.getContext("webgl2", {
@@ -592,6 +591,8 @@ var setupWebGL = (canvas) => {
592
591
  premultipliedAlpha: true
593
592
  });
594
593
  let blurRadius = null;
594
+ let maskBlurRadius = 8;
595
+ const downsampleFactor = 4;
595
596
  if (!gl) {
596
597
  console.error("Failed to create WebGL context");
597
598
  return void 0;
@@ -620,27 +621,36 @@ var setupWebGL = (canvas) => {
620
621
  }
621
622
  let bgBlurTextures = [];
622
623
  let bgBlurFrameBuffers = [];
623
- let maskBlurTextures = [];
624
- let maskBlurFrameBuffers = [];
624
+ let blurredMaskTexture = null;
625
+ let finalMaskTextures = [];
626
+ let readMaskIndex = 0;
627
+ let writeMaskIndex = 1;
625
628
  bgBlurTextures.push(initTexture(gl, 3));
626
629
  bgBlurTextures.push(initTexture(gl, 4));
627
- bgBlurFrameBuffers.push(createFramebuffer(gl, bgBlurTextures[0], canvas.width, canvas.height));
628
- bgBlurFrameBuffers.push(createFramebuffer(gl, bgBlurTextures[1], canvas.width, canvas.height));
629
- maskBlurTextures.push(initTexture(gl, 5));
630
- maskBlurTextures.push(initTexture(gl, 6));
631
- maskBlurFrameBuffers.push(
632
- createFramebuffer(gl, maskBlurTextures[0], canvas.width, canvas.height)
630
+ const bgBlurTextureWidth = Math.floor(canvas.width / downsampleFactor);
631
+ const bgBlurTextureHeight = Math.floor(canvas.height / downsampleFactor);
632
+ const downSampler = createDownSampler(gl, bgBlurTextureWidth, bgBlurTextureHeight);
633
+ bgBlurFrameBuffers.push(
634
+ createFramebuffer(gl, bgBlurTextures[0], bgBlurTextureWidth, bgBlurTextureHeight)
633
635
  );
634
- maskBlurFrameBuffers.push(
635
- createFramebuffer(gl, maskBlurTextures[1], canvas.width, canvas.height)
636
+ bgBlurFrameBuffers.push(
637
+ createFramebuffer(gl, bgBlurTextures[1], bgBlurTextureWidth, bgBlurTextureHeight)
636
638
  );
639
+ const tempMaskTexture = initTexture(gl, 5);
640
+ const tempMaskFrameBuffer = createFramebuffer(gl, tempMaskTexture, canvas.width, canvas.height);
641
+ finalMaskTextures.push(initTexture(gl, 6));
642
+ finalMaskTextures.push(initTexture(gl, 7));
643
+ const finalMaskFrameBuffers = [
644
+ createFramebuffer(gl, finalMaskTextures[0], canvas.width, canvas.height),
645
+ createFramebuffer(gl, finalMaskTextures[1], canvas.width, canvas.height)
646
+ ];
637
647
  gl.useProgram(compositeProgram);
638
648
  gl.uniform1i(bgTextureLocation, 0);
639
649
  gl.uniform1i(frameTextureLocation, 1);
640
650
  gl.uniform1i(maskTextureLocation, 2);
641
651
  let customBackgroundImage = emptyImageData;
642
- function render(frame, mask) {
643
- if (frame.codedWidth === 0 || mask.width === 0) {
652
+ function renderFrame(frame) {
653
+ if (frame.codedWidth === 0 || finalMaskTextures.length === 0) {
644
654
  return;
645
655
  }
646
656
  const width = frame.displayWidth;
@@ -650,11 +660,19 @@ var setupWebGL = (canvas) => {
650
660
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, frame);
651
661
  let backgroundTexture = bgTexture;
652
662
  if (blurRadius) {
653
- backgroundTexture = applyBlur(
663
+ const downSampledFrameTexture = applyDownsampling(
654
664
  gl,
655
665
  frameTexture,
656
- width,
657
- height,
666
+ downSampler,
667
+ vertexBuffer,
668
+ bgBlurTextureWidth,
669
+ bgBlurTextureHeight
670
+ );
671
+ backgroundTexture = applyBlur(
672
+ gl,
673
+ downSampledFrameTexture,
674
+ bgBlurTextureWidth,
675
+ bgBlurTextureHeight,
658
676
  blurRadius,
659
677
  blurProgram,
660
678
  blurUniforms,
@@ -668,19 +686,6 @@ var setupWebGL = (canvas) => {
668
686
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, customBackgroundImage);
669
687
  backgroundTexture = bgTexture;
670
688
  }
671
- const blurredMaskTexture = applyBlur(
672
- gl,
673
- mask.getAsWebGLTexture(),
674
- width,
675
- height,
676
- blurRadius || 1,
677
- // Use a default blur radius if not set
678
- boxBlurProgram,
679
- boxBlurUniforms,
680
- vertexBuffer,
681
- maskBlurFrameBuffers,
682
- maskBlurTextures
683
- );
684
689
  gl.viewport(0, 0, width, height);
685
690
  gl.clearColor(1, 1, 1, 1);
686
691
  gl.clear(gl.COLOR_BUFFER_BIT);
@@ -695,10 +700,9 @@ var setupWebGL = (canvas) => {
695
700
  gl.bindTexture(gl.TEXTURE_2D, frameTexture);
696
701
  gl.uniform1i(frameTextureLocation, 1);
697
702
  gl.activeTexture(gl.TEXTURE2);
698
- gl.bindTexture(gl.TEXTURE_2D, blurredMaskTexture);
703
+ gl.bindTexture(gl.TEXTURE_2D, finalMaskTextures[readMaskIndex]);
699
704
  gl.uniform1i(maskTextureLocation, 2);
700
705
  gl.drawArrays(gl.TRIANGLES, 0, 6);
701
- mask.close();
702
706
  }
703
707
  async function setBackgroundImage(image) {
704
708
  customBackgroundImage = emptyImageData;
@@ -718,28 +722,56 @@ var setupWebGL = (canvas) => {
718
722
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, customBackgroundImage);
719
723
  }
720
724
  function setBlurRadius(radius) {
721
- blurRadius = radius;
725
+ blurRadius = radius ? Math.max(1, Math.floor(radius / downsampleFactor)) : null;
722
726
  setBackgroundImage(null);
723
727
  }
728
+ function updateMask(mask) {
729
+ const tempFramebuffers = [tempMaskFrameBuffer, finalMaskFrameBuffers[writeMaskIndex]];
730
+ const tempTextures = [tempMaskTexture, finalMaskTextures[writeMaskIndex]];
731
+ applyBlur(
732
+ gl,
733
+ mask,
734
+ canvas.width,
735
+ canvas.height,
736
+ maskBlurRadius || 1,
737
+ boxBlurProgram,
738
+ boxBlurUniforms,
739
+ vertexBuffer,
740
+ tempFramebuffers,
741
+ tempTextures
742
+ );
743
+ readMaskIndex = writeMaskIndex;
744
+ writeMaskIndex = 1 - writeMaskIndex;
745
+ }
724
746
  function cleanup() {
725
747
  gl.deleteProgram(compositeProgram);
726
748
  gl.deleteProgram(blurProgram);
727
749
  gl.deleteProgram(boxBlurProgram);
728
750
  gl.deleteTexture(bgTexture);
729
751
  gl.deleteTexture(frameTexture);
752
+ gl.deleteTexture(tempMaskTexture);
753
+ gl.deleteFramebuffer(tempMaskFrameBuffer);
730
754
  for (const texture of bgBlurTextures) {
731
755
  gl.deleteTexture(texture);
732
756
  }
733
757
  for (const framebuffer of bgBlurFrameBuffers) {
734
758
  gl.deleteFramebuffer(framebuffer);
735
759
  }
736
- for (const texture of maskBlurTextures) {
760
+ for (const texture of finalMaskTextures) {
737
761
  gl.deleteTexture(texture);
738
762
  }
739
- for (const framebuffer of maskBlurFrameBuffers) {
763
+ for (const framebuffer of finalMaskFrameBuffers) {
740
764
  gl.deleteFramebuffer(framebuffer);
741
765
  }
742
766
  gl.deleteBuffer(vertexBuffer);
767
+ if (blurredMaskTexture) {
768
+ gl.deleteTexture(blurredMaskTexture);
769
+ }
770
+ if (downSampler) {
771
+ gl.deleteTexture(downSampler.texture);
772
+ gl.deleteFramebuffer(downSampler.framebuffer);
773
+ gl.deleteProgram(downSampler.program);
774
+ }
743
775
  if (customBackgroundImage) {
744
776
  if (customBackgroundImage instanceof ImageBitmap) {
745
777
  customBackgroundImage.close();
@@ -748,10 +780,9 @@ var setupWebGL = (canvas) => {
748
780
  }
749
781
  bgBlurTextures = [];
750
782
  bgBlurFrameBuffers = [];
751
- maskBlurTextures = [];
752
- maskBlurFrameBuffers = [];
783
+ finalMaskTextures = [];
753
784
  }
754
- return { render, setBackgroundImage, setBlurRadius, cleanup };
785
+ return { renderFrame, updateMask, setBackgroundImage, setBlurRadius, cleanup };
755
786
  };
756
787
 
757
788
  // src/transformers/VideoTransformer.ts
@@ -802,6 +833,7 @@ var BackgroundProcessor = class extends VideoTransformer {
802
833
  constructor(opts) {
803
834
  super();
804
835
  this.backgroundImage = null;
836
+ this.segmentationTimeMs = 0;
805
837
  this.options = opts;
806
838
  this.update(opts);
807
839
  }
@@ -853,7 +885,7 @@ var BackgroundProcessor = class extends VideoTransformer {
853
885
  (_a = this.gl) == null ? void 0 : _a.setBackgroundImage(imageData);
854
886
  }
855
887
  async transform(frame, controller) {
856
- var _a;
888
+ var _a, _b;
857
889
  try {
858
890
  if (!(frame instanceof VideoFrame) || frame.codedWidth === 0 || frame.codedHeight === 0) {
859
891
  console.debug("empty frame detected, ignoring");
@@ -863,37 +895,49 @@ var BackgroundProcessor = class extends VideoTransformer {
863
895
  controller.enqueue(frame);
864
896
  return;
865
897
  }
898
+ const frameTimeMs = Date.now();
866
899
  if (!this.canvas) {
867
900
  throw TypeError("Canvas needs to be initialized first");
868
901
  }
869
902
  this.canvas.width = frame.displayWidth;
870
903
  this.canvas.height = frame.displayHeight;
871
- let startTimeMs = performance.now();
872
- (_a = this.imageSegmenter) == null ? void 0 : _a.segmentForVideo(frame, startTimeMs, (result) => {
873
- var _a2, _b;
874
- const segmentationTimeMs = performance.now() - startTimeMs;
875
- this.segmentationResults = result;
876
- this.drawFrame(frame);
877
- if (this.canvas && this.canvas.width > 0 && this.canvas.height > 0) {
878
- const newFrame = new VideoFrame(this.canvas, {
879
- timestamp: frame.timestamp || Date.now()
904
+ const segmentationPromise = new Promise((resolve, reject) => {
905
+ var _a2;
906
+ try {
907
+ let segmentationStartTimeMs = performance.now();
908
+ (_a2 = this.imageSegmenter) == null ? void 0 : _a2.segmentForVideo(frame, segmentationStartTimeMs, (result) => {
909
+ this.segmentationTimeMs = performance.now() - segmentationStartTimeMs;
910
+ this.segmentationResults = result;
911
+ this.updateMask(result.categoryMask);
912
+ result.close();
913
+ resolve();
880
914
  });
881
- const filterTimeMs = performance.now() - startTimeMs - segmentationTimeMs;
882
- const stats = {
883
- processingTimeMs: performance.now() - startTimeMs,
884
- segmentationTimeMs,
885
- filterTimeMs
886
- };
887
- (_b = (_a2 = this.options).onFrameProcessed) == null ? void 0 : _b.call(_a2, stats);
888
- controller.enqueue(newFrame);
889
- } else {
890
- controller.enqueue(frame);
915
+ } catch (e) {
916
+ reject(e);
891
917
  }
892
- frame.close();
893
918
  });
919
+ const filterStartTimeMs = performance.now();
920
+ this.drawFrame(frame);
921
+ if (this.canvas && this.canvas.width > 0 && this.canvas.height > 0) {
922
+ const newFrame = new VideoFrame(this.canvas, {
923
+ timestamp: frame.timestamp || frameTimeMs
924
+ });
925
+ controller.enqueue(newFrame);
926
+ const filterTimeMs = performance.now() - filterStartTimeMs;
927
+ const stats = {
928
+ processingTimeMs: this.segmentationTimeMs + filterTimeMs,
929
+ segmentationTimeMs: this.segmentationTimeMs,
930
+ filterTimeMs
931
+ };
932
+ (_b = (_a = this.options).onFrameProcessed) == null ? void 0 : _b.call(_a, stats);
933
+ } else {
934
+ controller.enqueue(frame);
935
+ }
936
+ await segmentationPromise;
894
937
  } catch (e) {
895
938
  console.error("Error while processing frame: ", e);
896
- frame == null ? void 0 : frame.close();
939
+ } finally {
940
+ frame.close();
897
941
  }
898
942
  }
899
943
  async update(opts) {
@@ -906,12 +950,16 @@ var BackgroundProcessor = class extends VideoTransformer {
906
950
  }
907
951
  }
908
952
  async drawFrame(frame) {
909
- if (!this.canvas || !this.gl || !this.segmentationResults || !this.inputVideo)
953
+ var _a;
954
+ if (!this.gl)
910
955
  return;
911
- const mask = this.segmentationResults.categoryMask;
912
- if (mask) {
913
- this.gl.render(frame, mask);
914
- }
956
+ (_a = this.gl) == null ? void 0 : _a.renderFrame(frame);
957
+ }
958
+ async updateMask(mask) {
959
+ var _a;
960
+ if (!mask)
961
+ return;
962
+ (_a = this.gl) == null ? void 0 : _a.updateMask(mask.getAsWebGLTexture());
915
963
  }
916
964
  };
917
965