@motion-script/web 0.1.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.
- package/README.md +47 -0
- package/dist/audio/player.d.ts +43 -0
- package/dist/audio/player.d.ts.map +1 -0
- package/dist/audio/player.js +165 -0
- package/dist/audio/player.js.map +1 -0
- package/dist/effects/bloom.d.ts +19 -0
- package/dist/effects/bloom.d.ts.map +1 -0
- package/dist/effects/bloom.js +64 -0
- package/dist/effects/bloom.js.map +1 -0
- package/dist/effects/blur.d.ts +8 -0
- package/dist/effects/blur.d.ts.map +1 -0
- package/dist/effects/blur.js +12 -0
- package/dist/effects/blur.js.map +1 -0
- package/dist/effects/bulge-pinch.d.ts +20 -0
- package/dist/effects/bulge-pinch.d.ts.map +1 -0
- package/dist/effects/bulge-pinch.js +86 -0
- package/dist/effects/bulge-pinch.js.map +1 -0
- package/dist/effects/chromatic-aberration.d.ts +19 -0
- package/dist/effects/chromatic-aberration.d.ts.map +1 -0
- package/dist/effects/chromatic-aberration.js +59 -0
- package/dist/effects/chromatic-aberration.js.map +1 -0
- package/dist/effects/effect.d.ts +32 -0
- package/dist/effects/effect.d.ts.map +1 -0
- package/dist/effects/effect.js +22 -0
- package/dist/effects/effect.js.map +1 -0
- package/dist/effects/grayscale.d.ts +12 -0
- package/dist/effects/grayscale.d.ts.map +1 -0
- package/dist/effects/grayscale.js +31 -0
- package/dist/effects/grayscale.js.map +1 -0
- package/dist/effects/index.d.ts +13 -0
- package/dist/effects/index.d.ts.map +1 -0
- package/dist/effects/index.js +13 -0
- package/dist/effects/index.js.map +1 -0
- package/dist/effects/pixelate.d.ts +23 -0
- package/dist/effects/pixelate.d.ts.map +1 -0
- package/dist/effects/pixelate.js +37 -0
- package/dist/effects/pixelate.js.map +1 -0
- package/dist/effects/registry.d.ts +17 -0
- package/dist/effects/registry.d.ts.map +1 -0
- package/dist/effects/registry.js +56 -0
- package/dist/effects/registry.js.map +1 -0
- package/dist/effects/sksl-cache.d.ts +6 -0
- package/dist/effects/sksl-cache.d.ts.map +1 -0
- package/dist/effects/sksl-cache.js +21 -0
- package/dist/effects/sksl-cache.js.map +1 -0
- package/dist/effects/sksl-layer.d.ts +30 -0
- package/dist/effects/sksl-layer.d.ts.map +1 -0
- package/dist/effects/sksl-layer.js +82 -0
- package/dist/effects/sksl-layer.js.map +1 -0
- package/dist/effects/texture.d.ts +31 -0
- package/dist/effects/texture.d.ts.map +1 -0
- package/dist/effects/texture.js +66 -0
- package/dist/effects/texture.js.map +1 -0
- package/dist/effects/vintage.d.ts +20 -0
- package/dist/effects/vintage.d.ts.map +1 -0
- package/dist/effects/vintage.js +47 -0
- package/dist/effects/vintage.js.map +1 -0
- package/dist/effects/zoom.d.ts +20 -0
- package/dist/effects/zoom.d.ts.map +1 -0
- package/dist/effects/zoom.js +65 -0
- package/dist/effects/zoom.js.map +1 -0
- package/dist/exporter.d.ts +24 -0
- package/dist/exporter.d.ts.map +1 -0
- package/dist/exporter.js +177 -0
- package/dist/exporter.js.map +1 -0
- package/dist/fills/conic-gradient.d.ts +12 -0
- package/dist/fills/conic-gradient.d.ts.map +1 -0
- package/dist/fills/conic-gradient.js +44 -0
- package/dist/fills/conic-gradient.js.map +1 -0
- package/dist/fills/filters/alpha.d.ts +9 -0
- package/dist/fills/filters/alpha.d.ts.map +1 -0
- package/dist/fills/filters/alpha.js +21 -0
- package/dist/fills/filters/alpha.js.map +1 -0
- package/dist/fills/filters/blur.d.ts +9 -0
- package/dist/fills/filters/blur.d.ts.map +1 -0
- package/dist/fills/filters/blur.js +12 -0
- package/dist/fills/filters/blur.js.map +1 -0
- package/dist/fills/filters/color-adjustment.d.ts +14 -0
- package/dist/fills/filters/color-adjustment.d.ts.map +1 -0
- package/dist/fills/filters/color-adjustment.js +147 -0
- package/dist/fills/filters/color-adjustment.js.map +1 -0
- package/dist/fills/filters/color-matrix.d.ts +9 -0
- package/dist/fills/filters/color-matrix.d.ts.map +1 -0
- package/dist/fills/filters/color-matrix.js +14 -0
- package/dist/fills/filters/color-matrix.js.map +1 -0
- package/dist/fills/filters/curves.d.ts +9 -0
- package/dist/fills/filters/curves.d.ts.map +1 -0
- package/dist/fills/filters/curves.js +89 -0
- package/dist/fills/filters/curves.js.map +1 -0
- package/dist/fills/filters/exposure.d.ts +9 -0
- package/dist/fills/filters/exposure.d.ts.map +1 -0
- package/dist/fills/filters/exposure.js +22 -0
- package/dist/fills/filters/exposure.js.map +1 -0
- package/dist/fills/filters/filter.d.ts +17 -0
- package/dist/fills/filters/filter.d.ts.map +1 -0
- package/dist/fills/filters/filter.js +16 -0
- package/dist/fills/filters/filter.js.map +1 -0
- package/dist/fills/filters/grayscale.d.ts +9 -0
- package/dist/fills/filters/grayscale.d.ts.map +1 -0
- package/dist/fills/filters/grayscale.js +25 -0
- package/dist/fills/filters/grayscale.js.map +1 -0
- package/dist/fills/filters/registry.d.ts +16 -0
- package/dist/fills/filters/registry.d.ts.map +1 -0
- package/dist/fills/filters/registry.js +50 -0
- package/dist/fills/filters/registry.js.map +1 -0
- package/dist/fills/gradient-cache.d.ts +29 -0
- package/dist/fills/gradient-cache.d.ts.map +1 -0
- package/dist/fills/gradient-cache.js +57 -0
- package/dist/fills/gradient-cache.js.map +1 -0
- package/dist/fills/handler.d.ts +49 -0
- package/dist/fills/handler.d.ts.map +1 -0
- package/dist/fills/handler.js +172 -0
- package/dist/fills/handler.js.map +1 -0
- package/dist/fills/image.d.ts +34 -0
- package/dist/fills/image.d.ts.map +1 -0
- package/dist/fills/image.js +91 -0
- package/dist/fills/image.js.map +1 -0
- package/dist/fills/linear-gradient.d.ts +12 -0
- package/dist/fills/linear-gradient.d.ts.map +1 -0
- package/dist/fills/linear-gradient.js +48 -0
- package/dist/fills/linear-gradient.js.map +1 -0
- package/dist/fills/noise.d.ts +11 -0
- package/dist/fills/noise.d.ts.map +1 -0
- package/dist/fills/noise.js +82 -0
- package/dist/fills/noise.js.map +1 -0
- package/dist/fills/radial-gradient.d.ts +9 -0
- package/dist/fills/radial-gradient.d.ts.map +1 -0
- package/dist/fills/radial-gradient.js +43 -0
- package/dist/fills/radial-gradient.js.map +1 -0
- package/dist/fills/registry.d.ts +10 -0
- package/dist/fills/registry.d.ts.map +1 -0
- package/dist/fills/registry.js +34 -0
- package/dist/fills/registry.js.map +1 -0
- package/dist/fills/renderer.d.ts +24 -0
- package/dist/fills/renderer.d.ts.map +1 -0
- package/dist/fills/renderer.js +5 -0
- package/dist/fills/renderer.js.map +1 -0
- package/dist/fills/solid.d.ts +7 -0
- package/dist/fills/solid.d.ts.map +1 -0
- package/dist/fills/solid.js +13 -0
- package/dist/fills/solid.js.map +1 -0
- package/dist/fills/stripe.d.ts +7 -0
- package/dist/fills/stripe.d.ts.map +1 -0
- package/dist/fills/stripe.js +85 -0
- package/dist/fills/stripe.js.map +1 -0
- package/dist/fills/video.d.ts +6 -0
- package/dist/fills/video.d.ts.map +1 -0
- package/dist/fills/video.js +14 -0
- package/dist/fills/video.js.map +1 -0
- package/dist/font-style.d.ts +23 -0
- package/dist/font-style.d.ts.map +1 -0
- package/dist/font-style.js +34 -0
- package/dist/font-style.js.map +1 -0
- package/dist/getter.d.ts +9 -0
- package/dist/getter.d.ts.map +1 -0
- package/dist/getter.js +26 -0
- package/dist/getter.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/master-clock.d.ts +42 -0
- package/dist/master-clock.d.ts.map +1 -0
- package/dist/master-clock.js +134 -0
- package/dist/master-clock.js.map +1 -0
- package/dist/measure-scope.d.ts +14 -0
- package/dist/measure-scope.d.ts.map +1 -0
- package/dist/measure-scope.js +29 -0
- package/dist/measure-scope.js.map +1 -0
- package/dist/render-context.d.ts +107 -0
- package/dist/render-context.d.ts.map +1 -0
- package/dist/render-context.js +940 -0
- package/dist/render-context.js.map +1 -0
- package/dist/shapes/alpha-contour.d.ts +27 -0
- package/dist/shapes/alpha-contour.d.ts.map +1 -0
- package/dist/shapes/alpha-contour.js +330 -0
- package/dist/shapes/alpha-contour.js.map +1 -0
- package/dist/shapes/base.d.ts +46 -0
- package/dist/shapes/base.d.ts.map +1 -0
- package/dist/shapes/base.js +95 -0
- package/dist/shapes/base.js.map +1 -0
- package/dist/shapes/boolean.d.ts +28 -0
- package/dist/shapes/boolean.d.ts.map +1 -0
- package/dist/shapes/boolean.js +90 -0
- package/dist/shapes/boolean.js.map +1 -0
- package/dist/shapes/ellipse.d.ts +32 -0
- package/dist/shapes/ellipse.d.ts.map +1 -0
- package/dist/shapes/ellipse.js +50 -0
- package/dist/shapes/ellipse.js.map +1 -0
- package/dist/shapes/image.d.ts +66 -0
- package/dist/shapes/image.d.ts.map +1 -0
- package/dist/shapes/image.js +214 -0
- package/dist/shapes/image.js.map +1 -0
- package/dist/shapes/index.d.ts +67 -0
- package/dist/shapes/index.d.ts.map +1 -0
- package/dist/shapes/index.js +297 -0
- package/dist/shapes/index.js.map +1 -0
- package/dist/shapes/line.d.ts +25 -0
- package/dist/shapes/line.d.ts.map +1 -0
- package/dist/shapes/line.js +87 -0
- package/dist/shapes/line.js.map +1 -0
- package/dist/shapes/mask.d.ts +28 -0
- package/dist/shapes/mask.d.ts.map +1 -0
- package/dist/shapes/mask.js +106 -0
- package/dist/shapes/mask.js.map +1 -0
- package/dist/shapes/paragraph-layout.d.ts +64 -0
- package/dist/shapes/paragraph-layout.d.ts.map +1 -0
- package/dist/shapes/paragraph-layout.js +156 -0
- package/dist/shapes/paragraph-layout.js.map +1 -0
- package/dist/shapes/path.d.ts +29 -0
- package/dist/shapes/path.d.ts.map +1 -0
- package/dist/shapes/path.js +71 -0
- package/dist/shapes/path.js.map +1 -0
- package/dist/shapes/polygon.d.ts +33 -0
- package/dist/shapes/polygon.d.ts.map +1 -0
- package/dist/shapes/polygon.js +86 -0
- package/dist/shapes/polygon.js.map +1 -0
- package/dist/shapes/polygram.d.ts +34 -0
- package/dist/shapes/polygram.d.ts.map +1 -0
- package/dist/shapes/polygram.js +90 -0
- package/dist/shapes/polygram.js.map +1 -0
- package/dist/shapes/rect.d.ts +41 -0
- package/dist/shapes/rect.d.ts.map +1 -0
- package/dist/shapes/rect.js +111 -0
- package/dist/shapes/rect.js.map +1 -0
- package/dist/shapes/richtext.d.ts +28 -0
- package/dist/shapes/richtext.d.ts.map +1 -0
- package/dist/shapes/richtext.js +32 -0
- package/dist/shapes/richtext.js.map +1 -0
- package/dist/shapes/shape-handler.d.ts +79 -0
- package/dist/shapes/shape-handler.d.ts.map +1 -0
- package/dist/shapes/shape-handler.js +304 -0
- package/dist/shapes/shape-handler.js.map +1 -0
- package/dist/shapes/text.d.ts +13 -0
- package/dist/shapes/text.d.ts.map +1 -0
- package/dist/shapes/text.js +67 -0
- package/dist/shapes/text.js.map +1 -0
- package/dist/shapes/trim.d.ts +10 -0
- package/dist/shapes/trim.d.ts.map +1 -0
- package/dist/shapes/trim.js +49 -0
- package/dist/shapes/trim.js.map +1 -0
- package/dist/storage-adapter.d.ts +56 -0
- package/dist/storage-adapter.d.ts.map +1 -0
- package/dist/storage-adapter.js +188 -0
- package/dist/storage-adapter.js.map +1 -0
- package/dist/stroke/index.d.ts +34 -0
- package/dist/stroke/index.d.ts.map +1 -0
- package/dist/stroke/index.js +360 -0
- package/dist/stroke/index.js.map +1 -0
- package/dist/stroke/stroke-handler.d.ts +45 -0
- package/dist/stroke/stroke-handler.d.ts.map +1 -0
- package/dist/stroke/stroke-handler.js +371 -0
- package/dist/stroke/stroke-handler.js.map +1 -0
- package/dist/video/extract.d.ts +54 -0
- package/dist/video/extract.d.ts.map +1 -0
- package/dist/video/extract.js +192 -0
- package/dist/video/extract.js.map +1 -0
- package/dist/video/extract.worker.d.ts +50 -0
- package/dist/video/extract.worker.d.ts.map +1 -0
- package/dist/video/extract.worker.js +224 -0
- package/dist/video/extract.worker.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
import { FillRenderRegistry } from "../fills/registry";
|
|
2
|
+
/**
|
|
3
|
+
* Paints strokes and shadows over shape silhouettes. Handles the gritty parts
|
|
4
|
+
* of vector stroking on Skia: sub-pixel-width strokes are rasterized as filled
|
|
5
|
+
* paths for uniform AA (see {@link drawStroke}), thin strokes get pixel-grid
|
|
6
|
+
* snapped (see {@link snapPath}), dashes are length-fit per contour, and text
|
|
7
|
+
* gets a synthesized union outline since glyph paths aren't directly available
|
|
8
|
+
* (see {@link drawTextUnionStroke}). Delegates shader/paint setup for fills to
|
|
9
|
+
* {@link FillHandler}.
|
|
10
|
+
*/
|
|
11
|
+
export class StrokeHandler {
|
|
12
|
+
canvasKit;
|
|
13
|
+
getCanvas;
|
|
14
|
+
getPaint;
|
|
15
|
+
fills;
|
|
16
|
+
constructor(canvasKit, getCanvas, getPaint, fills) {
|
|
17
|
+
this.canvasKit = canvasKit;
|
|
18
|
+
this.getCanvas = getCanvas;
|
|
19
|
+
this.getPaint = getPaint;
|
|
20
|
+
this.fills = fills;
|
|
21
|
+
}
|
|
22
|
+
makeUniformDashEffect(path, dash, dashOffset = 0, fit) {
|
|
23
|
+
const info = fit ?? this.measureDashFit(path, dash);
|
|
24
|
+
if (!info)
|
|
25
|
+
return null;
|
|
26
|
+
return this.canvasKit.PathEffect.MakeDash(info.scaledDash, dashOffset * info.scale);
|
|
27
|
+
}
|
|
28
|
+
// Compute a per-contour-uniform dash pattern by scaling the dash array so an
|
|
29
|
+
// integer number of cycles fits the path length exactly.
|
|
30
|
+
measureDashFit(path, dash) {
|
|
31
|
+
const cycleLength = dash.reduce((a, b) => a + b, 0);
|
|
32
|
+
if (cycleLength <= 0)
|
|
33
|
+
return null;
|
|
34
|
+
let totalLength = 0;
|
|
35
|
+
const iter = new this.canvasKit.ContourMeasureIter(path, false, 1);
|
|
36
|
+
let contour = iter.next();
|
|
37
|
+
while (contour) {
|
|
38
|
+
totalLength += contour.length();
|
|
39
|
+
contour.delete();
|
|
40
|
+
contour = iter.next();
|
|
41
|
+
}
|
|
42
|
+
iter.delete();
|
|
43
|
+
if (totalLength <= 0)
|
|
44
|
+
return null;
|
|
45
|
+
const cycles = Math.max(1, Math.round(totalLength / cycleLength));
|
|
46
|
+
const scale = totalLength / (cycles * cycleLength);
|
|
47
|
+
return { scaledDash: dash.map(d => d * scale), scale };
|
|
48
|
+
}
|
|
49
|
+
// Build a path consisting of just the "on" dash segments along the original
|
|
50
|
+
// path. Used so we can run makeStroked() on a dashed path and draw the
|
|
51
|
+
// result as a fill (gives uniform AA on all sides). The caller owns the
|
|
52
|
+
// returned path and must delete() it.
|
|
53
|
+
buildDashedPath(path, dash, dashOffset, fit) {
|
|
54
|
+
const resolvedFit = fit ?? this.measureDashFit(path, dash);
|
|
55
|
+
if (!resolvedFit)
|
|
56
|
+
return null;
|
|
57
|
+
const { scaledDash, scale } = resolvedFit;
|
|
58
|
+
const cycle = scaledDash.reduce((a, b) => a + b, 0);
|
|
59
|
+
if (cycle <= 0)
|
|
60
|
+
return null;
|
|
61
|
+
const startOffset = ((dashOffset * scale) % cycle + cycle) % cycle;
|
|
62
|
+
const builder = new this.canvasKit.PathBuilder();
|
|
63
|
+
const iter = new this.canvasKit.ContourMeasureIter(path, false, 1);
|
|
64
|
+
let contour = iter.next();
|
|
65
|
+
let appended = false;
|
|
66
|
+
while (contour) {
|
|
67
|
+
const length = contour.length();
|
|
68
|
+
// Locate the dash segment that contains startOffset.
|
|
69
|
+
let dashIndex = 0;
|
|
70
|
+
let segStart = 0;
|
|
71
|
+
while (segStart + scaledDash[dashIndex] <= startOffset && dashIndex < scaledDash.length) {
|
|
72
|
+
segStart += scaledDash[dashIndex];
|
|
73
|
+
dashIndex = (dashIndex + 1) % scaledDash.length;
|
|
74
|
+
if (dashIndex === 0)
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
let dashRemaining = scaledDash[dashIndex] - (startOffset - segStart);
|
|
78
|
+
let drawing = dashIndex % 2 === 0;
|
|
79
|
+
let t = 0;
|
|
80
|
+
while (t < length - 1e-6) {
|
|
81
|
+
const segLen = Math.min(dashRemaining, length - t);
|
|
82
|
+
if (drawing && segLen > 1e-3) {
|
|
83
|
+
const seg = contour.getSegment(t, t + segLen, true);
|
|
84
|
+
if (seg) {
|
|
85
|
+
builder.addPath(seg);
|
|
86
|
+
seg.delete();
|
|
87
|
+
appended = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
t += segLen;
|
|
91
|
+
dashRemaining -= segLen;
|
|
92
|
+
if (dashRemaining <= 1e-6) {
|
|
93
|
+
dashIndex = (dashIndex + 1) % scaledDash.length;
|
|
94
|
+
dashRemaining = scaledDash[dashIndex];
|
|
95
|
+
drawing = !drawing;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
contour.delete();
|
|
99
|
+
contour = iter.next();
|
|
100
|
+
}
|
|
101
|
+
iter.delete();
|
|
102
|
+
if (!appended) {
|
|
103
|
+
builder.delete();
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return builder.detachAndDelete();
|
|
107
|
+
}
|
|
108
|
+
deviceMetrics(canvas) {
|
|
109
|
+
const m = canvas.getTotalMatrix();
|
|
110
|
+
return {
|
|
111
|
+
sx: Math.hypot(m[0], m[3]),
|
|
112
|
+
sy: Math.hypot(m[1], m[4]),
|
|
113
|
+
tx: m[2],
|
|
114
|
+
ty: m[5],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// For thin strokes (≤ ~2.5 device px), round to an integer device width
|
|
118
|
+
// ≥ 1 px and convert back to logical units. Returns the adjusted logical
|
|
119
|
+
// weight and the integer device width (or -1 when no snapping should occur).
|
|
120
|
+
resolveStrokeWidth(weight, deviceScale) {
|
|
121
|
+
if (weight <= 0 || deviceScale <= 0) {
|
|
122
|
+
return { logical: 0, intDeviceWidth: -1 };
|
|
123
|
+
}
|
|
124
|
+
const deviceWidth = weight * deviceScale;
|
|
125
|
+
if (deviceWidth >= 2.5) {
|
|
126
|
+
return { logical: weight, intDeviceWidth: -1 };
|
|
127
|
+
}
|
|
128
|
+
const intDeviceWidth = Math.max(1, Math.round(deviceWidth));
|
|
129
|
+
return { logical: intDeviceWidth / deviceScale, intDeviceWidth };
|
|
130
|
+
}
|
|
131
|
+
// Snap the canvas so the path's bounds land exactly on the device pixel
|
|
132
|
+
// grid — half-pixel offsets for odd stroke widths, integer for even — on
|
|
133
|
+
// ALL four sides. When the path's device-space size isn't already an
|
|
134
|
+
// integer we apply a sub-pixel scale around the top-left corner so right
|
|
135
|
+
// and bottom also align. Bails on rotated/skewed matrices since "pixel
|
|
136
|
+
// grid" isn't well defined there. Returns true if canvas.save() was called.
|
|
137
|
+
snapPath(canvas, intDeviceWidth, ckPath) {
|
|
138
|
+
if (intDeviceWidth <= 0 || !ckPath)
|
|
139
|
+
return false;
|
|
140
|
+
const m = canvas.getTotalMatrix();
|
|
141
|
+
if (Math.abs(m[1]) > 1e-6 || Math.abs(m[3]) > 1e-6)
|
|
142
|
+
return false;
|
|
143
|
+
const sx = m[0], sy = m[4], tx = m[2], ty = m[5];
|
|
144
|
+
if (sx === 0 || sy === 0)
|
|
145
|
+
return false;
|
|
146
|
+
const b = ckPath.getBounds();
|
|
147
|
+
const wLog = b[2] - b[0];
|
|
148
|
+
const hLog = b[3] - b[1];
|
|
149
|
+
if (wLog <= 0 || hLog <= 0)
|
|
150
|
+
return false;
|
|
151
|
+
const leftDev = tx + sx * b[0];
|
|
152
|
+
const topDev = ty + sy * b[1];
|
|
153
|
+
const rightDev = tx + sx * b[2];
|
|
154
|
+
const bottomDev = ty + sy * b[3];
|
|
155
|
+
const offset = intDeviceWidth % 2 === 0 ? 0 : 0.5;
|
|
156
|
+
const targetLeft = Math.round(leftDev - offset) + offset;
|
|
157
|
+
const targetTop = Math.round(topDev - offset) + offset;
|
|
158
|
+
const targetRight = Math.round(rightDev - offset) + offset;
|
|
159
|
+
const targetBottom = Math.round(bottomDev - offset) + offset;
|
|
160
|
+
// Refuse to snap if rounding would collapse the path.
|
|
161
|
+
if (targetRight - targetLeft < 1)
|
|
162
|
+
return false;
|
|
163
|
+
if (targetBottom - targetTop < 1)
|
|
164
|
+
return false;
|
|
165
|
+
const scaleX = (targetRight - targetLeft) / (rightDev - leftDev);
|
|
166
|
+
const scaleY = (targetBottom - targetTop) / (bottomDev - topDev);
|
|
167
|
+
// Skip when the path is already aligned.
|
|
168
|
+
if (Math.abs(scaleX - 1) < 1e-4
|
|
169
|
+
&& Math.abs(scaleY - 1) < 1e-4
|
|
170
|
+
&& Math.abs(targetLeft - leftDev) < 1e-4
|
|
171
|
+
&& Math.abs(targetTop - topDev) < 1e-4)
|
|
172
|
+
return false;
|
|
173
|
+
// Concat L such that current * L maps the path bounds to the targets.
|
|
174
|
+
// L is axis-aligned scale+translate in path-local space:
|
|
175
|
+
// L = [scaleX 0 c; 0 scaleY d; 0 0 1]
|
|
176
|
+
// where (scaleX, scaleY) makes device width/height integer and (c, d)
|
|
177
|
+
// shifts the top-left corner to (targetLeft, targetTop).
|
|
178
|
+
const c = (targetLeft - tx) / sx - scaleX * b[0];
|
|
179
|
+
const d = (targetTop - ty) / sy - scaleY * b[1];
|
|
180
|
+
canvas.save();
|
|
181
|
+
canvas.concat([scaleX, 0, c, 0, scaleY, d, 0, 0, 1]);
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
// `resolveBounds`, when supplied, returns the bounds a stroke's fill shader
|
|
185
|
+
// should resolve against for a given shape (driven by the fill's `space`).
|
|
186
|
+
// The shader is rebuilt per shape so each can resolve against its own rect;
|
|
187
|
+
// when omitted, bounds come from whatever the fill handler last set.
|
|
188
|
+
/** Paints each resolved stroke over every shape: resolves device-px stroke width (with thin-stroke snapping), builds the fill shader per shape via the registry, then draws through {@link drawStroke}. */
|
|
189
|
+
applyStrokes(strokes, shapes, resolveBounds) {
|
|
190
|
+
if (strokes.length === 0)
|
|
191
|
+
return false;
|
|
192
|
+
const canvas = this.getCanvas();
|
|
193
|
+
const paint = this.getPaint();
|
|
194
|
+
paint.setStyle(this.canvasKit.PaintStyle.Stroke);
|
|
195
|
+
const rendererCtx = this.fills.buildRendererCtx(paint);
|
|
196
|
+
for (const stroke of strokes) {
|
|
197
|
+
const weight = stroke.weight ?? 1;
|
|
198
|
+
const { sx, sy } = this.deviceMetrics(canvas);
|
|
199
|
+
const { logical, intDeviceWidth } = this.resolveStrokeWidth(weight, Math.max(sx, sy));
|
|
200
|
+
paint.setStrokeWidth(logical);
|
|
201
|
+
const opacity = stroke.fill.opacity !== undefined ? stroke.fill.opacity : 1.0;
|
|
202
|
+
paint.setAlphaf(opacity);
|
|
203
|
+
if (stroke.fill.blend) {
|
|
204
|
+
paint.setBlendMode(this.fills.getCanvasKitBlendMode(stroke.fill.blend));
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
paint.setBlendMode(this.canvasKit.BlendMode.SrcOver);
|
|
208
|
+
}
|
|
209
|
+
for (const shape of shapes) {
|
|
210
|
+
if (resolveBounds)
|
|
211
|
+
resolveBounds(stroke.fill, shape);
|
|
212
|
+
if (!FillRenderRegistry.applyPaint(stroke.fill, rendererCtx))
|
|
213
|
+
continue;
|
|
214
|
+
const snapped = this.snapPath(canvas, intDeviceWidth, shape.ckPath);
|
|
215
|
+
this.drawStroke(canvas, paint, shape, stroke, logical, intDeviceWidth);
|
|
216
|
+
if (snapped)
|
|
217
|
+
canvas.restore();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
paint.setBlendMode(this.canvasKit.BlendMode.SrcOver);
|
|
221
|
+
paint.setAlphaf(1.0);
|
|
222
|
+
paint.setShader(null);
|
|
223
|
+
paint.setStyle(this.canvasKit.PaintStyle.Stroke);
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
// Draw one stroke pass on one shape. For thin strokes (intDeviceWidth > 0)
|
|
227
|
+
// we convert the stroke to a filled path via Path.makeStroked() and draw it
|
|
228
|
+
// as a fill — fill rasterization gives uniform AA on every side, which the
|
|
229
|
+
// stroke rasterizer doesn't for sub-pixel widths. Dashed thin strokes get
|
|
230
|
+
// their dash pattern baked into a path first (buildDashedPath) so the same
|
|
231
|
+
// makeStroked trick works on them.
|
|
232
|
+
drawStroke(canvas, paint, shape, stroke, logicalWidth, intDeviceWidth) {
|
|
233
|
+
if (shape.isText) {
|
|
234
|
+
this.drawTextUnionStroke(canvas, paint, shape, stroke, logicalWidth);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const hasDash = !!(stroke.dash && stroke.dash.length > 0);
|
|
238
|
+
// Measure dash fit once; pass to both buildDashedPath and makeUniformDashEffect
|
|
239
|
+
// so the contour iteration runs only once per dashed shape.
|
|
240
|
+
const dashFit = hasDash && shape.ckPath
|
|
241
|
+
? this.measureDashFit(shape.ckPath, stroke.dash)
|
|
242
|
+
: null;
|
|
243
|
+
if (intDeviceWidth > 0 && shape.ckPath) {
|
|
244
|
+
const source = hasDash
|
|
245
|
+
? this.buildDashedPath(shape.ckPath, stroke.dash, stroke.dashOffset ?? 0, dashFit ?? undefined)
|
|
246
|
+
: shape.ckPath;
|
|
247
|
+
if (source) {
|
|
248
|
+
const filled = source.makeStroked({ width: logicalWidth });
|
|
249
|
+
if (source !== shape.ckPath)
|
|
250
|
+
source.delete();
|
|
251
|
+
if (filled) {
|
|
252
|
+
paint.setStyle(this.canvasKit.PaintStyle.Fill);
|
|
253
|
+
canvas.drawPath(filled, paint);
|
|
254
|
+
paint.setStyle(this.canvasKit.PaintStyle.Stroke);
|
|
255
|
+
filled.delete();
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Fallback for thick strokes or when makeStroked/dashing failed.
|
|
261
|
+
if (hasDash && shape.ckPath) {
|
|
262
|
+
const effect = this.makeUniformDashEffect(shape.ckPath, stroke.dash, stroke.dashOffset ?? 0, dashFit ?? undefined);
|
|
263
|
+
if (effect) {
|
|
264
|
+
paint.setPathEffect(effect);
|
|
265
|
+
canvas.drawPath(shape.ckPath, paint);
|
|
266
|
+
paint.setPathEffect(null);
|
|
267
|
+
effect.delete();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
shape.draw(paint);
|
|
272
|
+
}
|
|
273
|
+
// Strokes that follow the union of all glyph silhouettes, like Figma. We
|
|
274
|
+
// can't get glyph paths out of canvaskit-wasm to compute a real union, so
|
|
275
|
+
// we stroke each glyph at 2× width inside a saveLayer and then erase the
|
|
276
|
+
// interior (DstOut against the fill silhouette). What's left is an
|
|
277
|
+
// outside-aligned stroke of the requested width on the outer boundary of
|
|
278
|
+
// the union — internal crossings at overlapping glyphs disappear because
|
|
279
|
+
// they sit inside the silhouette and get erased.
|
|
280
|
+
//
|
|
281
|
+
// Dashed text strokes piggy-back on Skia's drawText → glyph-path fallback:
|
|
282
|
+
// setting PathEffect.MakeDash on the paint causes the stroke rasterizer to
|
|
283
|
+
// dash along each glyph's outline. We can't size the dash to the contour
|
|
284
|
+
// (no path to measure), so the dash array is used as-is.
|
|
285
|
+
drawTextUnionStroke(canvas, paint, shape, stroke, logicalWidth) {
|
|
286
|
+
const hasDash = !!(stroke.dash && stroke.dash.length > 0);
|
|
287
|
+
let dashEffect = null;
|
|
288
|
+
if (hasDash) {
|
|
289
|
+
dashEffect = this.canvasKit.PathEffect.MakeDash(stroke.dash, stroke.dashOffset ?? 0);
|
|
290
|
+
paint.setPathEffect(dashEffect);
|
|
291
|
+
}
|
|
292
|
+
canvas.saveLayer();
|
|
293
|
+
paint.setStrokeWidth(logicalWidth * 2);
|
|
294
|
+
shape.draw(paint);
|
|
295
|
+
const eraser = new this.canvasKit.Paint();
|
|
296
|
+
eraser.setStyle(this.canvasKit.PaintStyle.Fill);
|
|
297
|
+
eraser.setBlendMode(this.canvasKit.BlendMode.DstOut);
|
|
298
|
+
eraser.setColor(this.canvasKit.WHITE);
|
|
299
|
+
shape.draw(eraser);
|
|
300
|
+
eraser.delete();
|
|
301
|
+
canvas.restore();
|
|
302
|
+
paint.setStrokeWidth(logicalWidth);
|
|
303
|
+
if (dashEffect) {
|
|
304
|
+
paint.setPathEffect(null);
|
|
305
|
+
dashEffect.delete();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/** Paints drop shadows: for each shadow, offsets and optionally blurs a silhouette layer (filled shapes and/or strokes recolored to the shadow's fill/opacity), composited beneath the real paint via `saveLayer`. */
|
|
309
|
+
applyShadows(shadows, shapes, fills, strokes, resolveBounds) {
|
|
310
|
+
if (shadows.length === 0)
|
|
311
|
+
return;
|
|
312
|
+
const canvas = this.getCanvas();
|
|
313
|
+
const paint = this.getPaint();
|
|
314
|
+
const hasFill = fills.length > 0 && fills.some(f => (f.opacity ?? 1) > 0);
|
|
315
|
+
const hasStrokes = strokes.length > 0;
|
|
316
|
+
for (const shadow of shadows) {
|
|
317
|
+
const dx = shadow.dx ?? 0;
|
|
318
|
+
const dy = shadow.dy ?? 0;
|
|
319
|
+
const opacity = shadow.fill.opacity !== undefined ? shadow.fill.opacity : 1.0;
|
|
320
|
+
const layerPaint = new this.canvasKit.Paint();
|
|
321
|
+
layerPaint.setAlphaf(opacity);
|
|
322
|
+
if (shadow.blur > 0) {
|
|
323
|
+
const sigma = shadow.blur / 2;
|
|
324
|
+
const filter = this.canvasKit.ImageFilter.MakeBlur(sigma, sigma, this.canvasKit.TileMode.Decal, null);
|
|
325
|
+
layerPaint.setImageFilter(filter);
|
|
326
|
+
}
|
|
327
|
+
canvas.save();
|
|
328
|
+
// Scene coords are Y-up; the canvas is Y-down, so negate dy to keep
|
|
329
|
+
// a positive dy nudging the shadow upward.
|
|
330
|
+
canvas.translate(dx, -dy);
|
|
331
|
+
canvas.saveLayer(layerPaint);
|
|
332
|
+
paint.setAlphaf(1.0);
|
|
333
|
+
if (resolveBounds)
|
|
334
|
+
resolveBounds(shadow.fill, null);
|
|
335
|
+
FillRenderRegistry.applyPaint(shadow.fill, this.fills.buildRendererCtx(paint));
|
|
336
|
+
if (hasFill) {
|
|
337
|
+
paint.setStyle(this.canvasKit.PaintStyle.Fill);
|
|
338
|
+
paint.setPathEffect(null);
|
|
339
|
+
for (const shape of shapes)
|
|
340
|
+
shape.draw(paint);
|
|
341
|
+
}
|
|
342
|
+
if (hasStrokes) {
|
|
343
|
+
paint.setStyle(this.canvasKit.PaintStyle.Stroke);
|
|
344
|
+
for (const stroke of strokes) {
|
|
345
|
+
const weight = stroke.weight ?? 1;
|
|
346
|
+
const { sx, sy } = this.deviceMetrics(canvas);
|
|
347
|
+
const { logical, intDeviceWidth } = this.resolveStrokeWidth(weight, Math.max(sx, sy));
|
|
348
|
+
paint.setStrokeWidth(logical);
|
|
349
|
+
paint.setPathEffect(null);
|
|
350
|
+
// Shadow strokes inherit the shadow's silhouette colour set
|
|
351
|
+
// above — they are not painted with the real stroke fill.
|
|
352
|
+
for (const shape of shapes) {
|
|
353
|
+
const snapped = this.snapPath(canvas, intDeviceWidth, shape.ckPath);
|
|
354
|
+
this.drawStroke(canvas, paint, shape, stroke, logical, intDeviceWidth);
|
|
355
|
+
if (snapped)
|
|
356
|
+
canvas.restore();
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
canvas.restore();
|
|
361
|
+
canvas.restore();
|
|
362
|
+
layerPaint.delete();
|
|
363
|
+
}
|
|
364
|
+
paint.setStyle(this.canvasKit.PaintStyle.Fill);
|
|
365
|
+
paint.setPathEffect(null);
|
|
366
|
+
paint.setBlendMode(this.canvasKit.BlendMode.SrcOver);
|
|
367
|
+
paint.setAlphaf(1.0);
|
|
368
|
+
paint.setShader(null);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
//# sourceMappingURL=stroke-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stroke-handler.js","sourceRoot":"","sources":["../../src/stroke/stroke-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type ExtractSource = string | Blob;
|
|
2
|
+
export interface DecodedBitmap {
|
|
3
|
+
tsUs: number;
|
|
4
|
+
bitmap: ImageBitmap;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
export type FrameListener = (frame: DecodedBitmap) => void;
|
|
9
|
+
/**
|
|
10
|
+
* A live decoding session against a single video source. Frames are not
|
|
11
|
+
* pre-decoded — instead, callers request ranges around the current playhead
|
|
12
|
+
* via {@link decodeRange}, and a worker pumps frames into the registered
|
|
13
|
+
* listener as they arrive.
|
|
14
|
+
*
|
|
15
|
+
* Cancelling: a fresh `decodeRange` call bumps an internal generation; the
|
|
16
|
+
* worker's in-flight loop notices on its next yield and stops. This makes
|
|
17
|
+
* playhead jumps cheap — no need to wait out the previous range.
|
|
18
|
+
*/
|
|
19
|
+
export declare class VideoStream {
|
|
20
|
+
private readonly jobId;
|
|
21
|
+
private readonly src;
|
|
22
|
+
private readonly targetWidth?;
|
|
23
|
+
private readonly targetHeight?;
|
|
24
|
+
private listener;
|
|
25
|
+
/**
|
|
26
|
+
* Worker uses generation numbers to discard stale frames mid-decode.
|
|
27
|
+
* `expectedGeneration` is the latest one we asked for; any frame whose
|
|
28
|
+
* generation matches is delivered to the listener, others are closed.
|
|
29
|
+
*/
|
|
30
|
+
private expectedGeneration;
|
|
31
|
+
private openPromise;
|
|
32
|
+
private rangeWaiters;
|
|
33
|
+
private closed;
|
|
34
|
+
constructor(src: ExtractSource, targetWidth?: number, targetHeight?: number);
|
|
35
|
+
onFrame(cb: FrameListener): void;
|
|
36
|
+
open(): Promise<{
|
|
37
|
+
width: number;
|
|
38
|
+
height: number;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Ask the worker to decode the half-open range [startSeconds, endSeconds)
|
|
42
|
+
* at `fps`. Cancels any prior in-flight range for this stream. Returns a
|
|
43
|
+
* promise that resolves when this range is fully decoded.
|
|
44
|
+
*
|
|
45
|
+
* `skipBeforeTsUs`/`skipAfterTsUs` define a [from, to] microsecond window
|
|
46
|
+
* the caller already has cached — frames inside that window are decoded
|
|
47
|
+
* but not transferred to save bus traffic and GPU memory.
|
|
48
|
+
*/
|
|
49
|
+
decodeRange(startSeconds: number, endSeconds: number, fps: number, skipBeforeTsUs?: number, skipAfterTsUs?: number): Promise<void>;
|
|
50
|
+
/** Abort the current range without starting a new one. */
|
|
51
|
+
cancel(): void;
|
|
52
|
+
close(): void;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=extract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/video/extract.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,IAAI,CAAC;AAE1C,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;AAqE3D;;;;;;;;;GASG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;IACvC,OAAO,CAAC,QAAQ,CAA8B;IAE9C;;;;OAIG;IACH,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,WAAW,CAA2D;IAC9E,OAAO,CAAC,YAAY,CAAsF;IAE1G,OAAO,CAAC,MAAM,CAAkB;gBAEpB,GAAG,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;IAO3E,OAAO,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI;IAIhC,IAAI,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IA0ClD;;;;;;;;OAQG;IACH,WAAW,CACP,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,EACvB,aAAa,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC;IAmBhB,0DAA0D;IAC1D,MAAM,IAAI,IAAI;IAMd,KAAK,IAAI,IAAI;CAYhB"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// ─── Shared worker plumbing ──────────────────────────────────────────────────
|
|
2
|
+
let sharedWorker = null;
|
|
3
|
+
let workerUnavailable = false;
|
|
4
|
+
let nextJobId = 1;
|
|
5
|
+
const routers = new Map();
|
|
6
|
+
function getWorker() {
|
|
7
|
+
if (workerUnavailable)
|
|
8
|
+
return null;
|
|
9
|
+
if (sharedWorker)
|
|
10
|
+
return sharedWorker;
|
|
11
|
+
try {
|
|
12
|
+
sharedWorker = new Worker(new URL("./extract.worker.js", import.meta.url), {
|
|
13
|
+
type: "module",
|
|
14
|
+
});
|
|
15
|
+
sharedWorker.addEventListener("message", (event) => {
|
|
16
|
+
const msg = event.data;
|
|
17
|
+
const router = routers.get(msg.jobId);
|
|
18
|
+
if (!router) {
|
|
19
|
+
if (msg.type === "frame")
|
|
20
|
+
msg.bitmap.close();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
switch (msg.type) {
|
|
24
|
+
case "opened":
|
|
25
|
+
router.onOpened?.(msg.sourceWidth, msg.sourceHeight);
|
|
26
|
+
break;
|
|
27
|
+
case "frame":
|
|
28
|
+
router.onFrame?.(msg.tsUs, msg.bitmap, msg.width, msg.height, msg.generation);
|
|
29
|
+
break;
|
|
30
|
+
case "range-done":
|
|
31
|
+
router.onRangeDone?.(msg.generation);
|
|
32
|
+
break;
|
|
33
|
+
case "error":
|
|
34
|
+
router.onError?.(msg.message);
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
sharedWorker.addEventListener("error", (err) => {
|
|
39
|
+
workerUnavailable = true;
|
|
40
|
+
const message = err.message || "extract worker crashed";
|
|
41
|
+
for (const [, router] of routers)
|
|
42
|
+
router.onError?.(message);
|
|
43
|
+
routers.clear();
|
|
44
|
+
sharedWorker = null;
|
|
45
|
+
});
|
|
46
|
+
return sharedWorker;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
workerUnavailable = true;
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function send(req, transfer) {
|
|
54
|
+
const w = getWorker();
|
|
55
|
+
if (!w)
|
|
56
|
+
return false;
|
|
57
|
+
w.postMessage(req, transfer ?? []);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
// ─── VideoStream: one per source ─────────────────────────────────────────────
|
|
61
|
+
/**
|
|
62
|
+
* A live decoding session against a single video source. Frames are not
|
|
63
|
+
* pre-decoded — instead, callers request ranges around the current playhead
|
|
64
|
+
* via {@link decodeRange}, and a worker pumps frames into the registered
|
|
65
|
+
* listener as they arrive.
|
|
66
|
+
*
|
|
67
|
+
* Cancelling: a fresh `decodeRange` call bumps an internal generation; the
|
|
68
|
+
* worker's in-flight loop notices on its next yield and stops. This makes
|
|
69
|
+
* playhead jumps cheap — no need to wait out the previous range.
|
|
70
|
+
*/
|
|
71
|
+
export class VideoStream {
|
|
72
|
+
jobId;
|
|
73
|
+
src;
|
|
74
|
+
targetWidth;
|
|
75
|
+
targetHeight;
|
|
76
|
+
listener = null;
|
|
77
|
+
/**
|
|
78
|
+
* Worker uses generation numbers to discard stale frames mid-decode.
|
|
79
|
+
* `expectedGeneration` is the latest one we asked for; any frame whose
|
|
80
|
+
* generation matches is delivered to the listener, others are closed.
|
|
81
|
+
*/
|
|
82
|
+
expectedGeneration = 0;
|
|
83
|
+
openPromise = null;
|
|
84
|
+
rangeWaiters = [];
|
|
85
|
+
closed = false;
|
|
86
|
+
constructor(src, targetWidth, targetHeight) {
|
|
87
|
+
this.jobId = nextJobId++;
|
|
88
|
+
this.src = src;
|
|
89
|
+
this.targetWidth = targetWidth;
|
|
90
|
+
this.targetHeight = targetHeight;
|
|
91
|
+
}
|
|
92
|
+
onFrame(cb) {
|
|
93
|
+
this.listener = cb;
|
|
94
|
+
}
|
|
95
|
+
open() {
|
|
96
|
+
if (this.openPromise)
|
|
97
|
+
return this.openPromise;
|
|
98
|
+
this.openPromise = new Promise((resolve, reject) => {
|
|
99
|
+
const router = {
|
|
100
|
+
onOpened: (w, h) => resolve({ width: w, height: h }),
|
|
101
|
+
onFrame: (tsUs, bitmap, width, height, generation) => {
|
|
102
|
+
if (this.closed || generation !== this.expectedGeneration) {
|
|
103
|
+
bitmap.close();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this.listener?.({ tsUs, bitmap, width, height });
|
|
107
|
+
},
|
|
108
|
+
onRangeDone: (generation) => {
|
|
109
|
+
if (generation !== this.expectedGeneration)
|
|
110
|
+
return;
|
|
111
|
+
const waiters = this.rangeWaiters;
|
|
112
|
+
this.rangeWaiters = [];
|
|
113
|
+
for (const w of waiters) {
|
|
114
|
+
if (w.generation === generation)
|
|
115
|
+
w.resolve();
|
|
116
|
+
else
|
|
117
|
+
this.rangeWaiters.push(w);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
onError: (message) => {
|
|
121
|
+
const err = new Error(message);
|
|
122
|
+
const waiters = this.rangeWaiters;
|
|
123
|
+
this.rangeWaiters = [];
|
|
124
|
+
for (const w of waiters)
|
|
125
|
+
w.reject(err);
|
|
126
|
+
reject(err);
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
routers.set(this.jobId, router);
|
|
130
|
+
const sent = send({
|
|
131
|
+
type: "open",
|
|
132
|
+
jobId: this.jobId,
|
|
133
|
+
src: this.src,
|
|
134
|
+
targetWidth: this.targetWidth,
|
|
135
|
+
targetHeight: this.targetHeight,
|
|
136
|
+
});
|
|
137
|
+
if (!sent)
|
|
138
|
+
reject(new Error("video extract worker unavailable"));
|
|
139
|
+
});
|
|
140
|
+
return this.openPromise;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Ask the worker to decode the half-open range [startSeconds, endSeconds)
|
|
144
|
+
* at `fps`. Cancels any prior in-flight range for this stream. Returns a
|
|
145
|
+
* promise that resolves when this range is fully decoded.
|
|
146
|
+
*
|
|
147
|
+
* `skipBeforeTsUs`/`skipAfterTsUs` define a [from, to] microsecond window
|
|
148
|
+
* the caller already has cached — frames inside that window are decoded
|
|
149
|
+
* but not transferred to save bus traffic and GPU memory.
|
|
150
|
+
*/
|
|
151
|
+
decodeRange(startSeconds, endSeconds, fps, skipBeforeTsUs, skipAfterTsUs) {
|
|
152
|
+
if (this.closed)
|
|
153
|
+
return Promise.resolve();
|
|
154
|
+
const generation = ++this.expectedGeneration;
|
|
155
|
+
const done = new Promise((resolve, reject) => {
|
|
156
|
+
this.rangeWaiters.push({ generation, resolve, reject });
|
|
157
|
+
});
|
|
158
|
+
send({
|
|
159
|
+
type: "decode-range",
|
|
160
|
+
jobId: this.jobId,
|
|
161
|
+
generation,
|
|
162
|
+
startSeconds,
|
|
163
|
+
endSeconds,
|
|
164
|
+
fps,
|
|
165
|
+
skipBeforeTsUs,
|
|
166
|
+
skipAfterTsUs,
|
|
167
|
+
});
|
|
168
|
+
return done;
|
|
169
|
+
}
|
|
170
|
+
/** Abort the current range without starting a new one. */
|
|
171
|
+
cancel() {
|
|
172
|
+
if (this.closed)
|
|
173
|
+
return;
|
|
174
|
+
this.expectedGeneration++;
|
|
175
|
+
send({ type: "cancel-range", jobId: this.jobId });
|
|
176
|
+
}
|
|
177
|
+
close() {
|
|
178
|
+
if (this.closed)
|
|
179
|
+
return;
|
|
180
|
+
this.closed = true;
|
|
181
|
+
this.expectedGeneration++;
|
|
182
|
+
send({ type: "close", jobId: this.jobId });
|
|
183
|
+
routers.delete(this.jobId);
|
|
184
|
+
// Reject any outstanding waiters so callers don't hang.
|
|
185
|
+
const waiters = this.rangeWaiters;
|
|
186
|
+
this.rangeWaiters = [];
|
|
187
|
+
for (const w of waiters)
|
|
188
|
+
w.resolve();
|
|
189
|
+
this.listener = null;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/video/extract.ts"],"names":[],"mappings":"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"}
|