jassub 2.5.0 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/jassub.d.ts +1 -1
- package/dist/jassub.js +25 -26
- package/dist/jassub.js.map +1 -1
- package/dist/wasm/jassub-worker.js +177 -118
- package/dist/wasm/jassub-worker.js.map +1 -1
- package/dist/worker/util.d.ts +50 -5
- package/dist/worker/util.js +0 -5
- package/dist/worker/util.js.map +1 -1
- package/dist/worker/worker.d.ts +8 -9
- package/dist/worker/worker.js +36 -75
- package/dist/worker/worker.js.map +1 -1
- package/package.json +2 -2
- package/src/jassub.ts +18 -16
- package/src/wasm/types.d.ts +15 -79
- package/src/worker/util.ts +51 -10
- package/src/worker/worker.ts +44 -85
package/src/worker/worker.ts
CHANGED
|
@@ -8,7 +8,7 @@ import WASM from '../wasm/jassub-worker.js'
|
|
|
8
8
|
import { Canvas2DRenderer } from './renderers/2d-renderer.ts'
|
|
9
9
|
import { WebGL1Renderer } from './renderers/webgl1-renderer.ts'
|
|
10
10
|
import { WebGL2Renderer } from './renderers/webgl2-renderer.ts'
|
|
11
|
-
import {
|
|
11
|
+
import { _fetch, fetchtext, LIBASS_YCBCR_MAP, THREAD_COUNT, WEIGHT_MAP, type ASSEvent, type ASSImage, type ASSStyle, type WeightValue } from './util.ts'
|
|
12
12
|
|
|
13
13
|
import type { JASSUB, MainModule } from '../wasm/types.d.ts'
|
|
14
14
|
// import { WebGPURenderer } from './webgpu-renderer'
|
|
@@ -34,19 +34,22 @@ interface opts {
|
|
|
34
34
|
queryFonts: 'local' | 'localandremote' | false
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
const constructor = Symbol.for('constructor')
|
|
38
|
+
|
|
37
39
|
export class ASSRenderer {
|
|
38
|
-
_offCanvas?: OffscreenCanvas
|
|
39
40
|
_wasm!: JASSUB
|
|
40
41
|
_subtitleColorSpace?: 'BT601' | 'BT709' | 'SMPTE240M' | 'FCC' | null
|
|
41
42
|
_videoColorSpace?: 'BT709' | 'BT601'
|
|
42
43
|
_malloc!: (size: number) => number
|
|
43
|
-
_gpurender
|
|
44
|
+
_gpurender!: WebGL2Renderer | WebGL1Renderer | Canvas2DRenderer
|
|
44
45
|
|
|
45
46
|
debug = false
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
constructor (...args: [data: opts, getFont: (font: string, weight: WeightValue) => Promise<Uint8Array<ArrayBuffer> | undefined>, ctrl: OffscreenCanvas]) {
|
|
49
|
+
return this[constructor](...args) as unknown as this
|
|
50
|
+
}
|
|
48
51
|
|
|
49
|
-
constructor (data: opts, getFont: (font: string, weight: WeightValue) => Promise<Uint8Array<ArrayBuffer> | undefined
|
|
52
|
+
async [constructor] (data: opts, getFont: (font: string, weight: WeightValue) => Promise<Uint8Array<ArrayBuffer> | undefined>, ctrl: OffscreenCanvas) {
|
|
50
53
|
// remove case sensitivity
|
|
51
54
|
this._availableFonts = Object.fromEntries(Object.entries(data.availableFonts).map(([k, v]) => [k.trim().toLowerCase(), v]))
|
|
52
55
|
this.debug = data.debug
|
|
@@ -58,17 +61,6 @@ export class ASSRenderer {
|
|
|
58
61
|
const _fetch = globalThis.fetch
|
|
59
62
|
globalThis.fetch = _ => _fetch(data.wasmUrl)
|
|
60
63
|
|
|
61
|
-
// TODO: abslink doesnt support transferables yet
|
|
62
|
-
const handleMessage = ({ data }: MessageEvent) => {
|
|
63
|
-
if (data.name === 'offscreenCanvas') {
|
|
64
|
-
// await this._ready // needed for webGPU
|
|
65
|
-
this._offCanvas = data.ctrl
|
|
66
|
-
this._gpurender.setCanvas(this._offCanvas!)
|
|
67
|
-
removeEventListener('message', handleMessage)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
addEventListener('message', handleMessage)
|
|
71
|
-
|
|
72
64
|
// const devicePromise = navigator.gpu?.requestAdapter({
|
|
73
65
|
// powerPreference: 'high-performance'
|
|
74
66
|
// }).then(adapter => adapter?.requestDevice())
|
|
@@ -83,33 +75,30 @@ export class ASSRenderer {
|
|
|
83
75
|
this._gpurender = new Canvas2DRenderer()
|
|
84
76
|
}
|
|
85
77
|
|
|
78
|
+
this._gpurender.setCanvas(ctrl)
|
|
79
|
+
|
|
80
|
+
this._loadedInitialFonts = !data.fonts.length
|
|
86
81
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
const { _malloc, JASSUB } = await (WASM({ __url: data.wasmUrl, __out: (log: string) => this._log(log) }) as Promise<MainModule>)
|
|
83
|
+
this._malloc = _malloc
|
|
89
84
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
this._wasm = new JASSUB(data.width, data.height, this._defaultFont)
|
|
86
|
+
// Firefox seems to have issues with multithreading in workers
|
|
87
|
+
// a worker inside a worker does not recieve messages properly
|
|
88
|
+
this._wasm.setThreads(THREAD_COUNT)
|
|
94
89
|
|
|
95
|
-
|
|
90
|
+
if (!this._loadedInitialFonts) await this._loadInitialFonts(data.fonts)
|
|
96
91
|
|
|
97
|
-
|
|
92
|
+
this._wasm.createTrackMem(data.subContent ?? await fetchtext(data.subUrl!))
|
|
98
93
|
|
|
99
|
-
|
|
94
|
+
this._subtitleColorSpace = LIBASS_YCBCR_MAP[this._wasm.trackColorSpace]
|
|
100
95
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// this._gpurender = device ? new WebGPURenderer(device) : new WebGL2Renderer()
|
|
106
|
-
// if (this._offCanvas) this._gpurender.setCanvas(this._offCanvas, this._offCanvas.width, this._offCanvas.height)
|
|
107
|
-
this._checkColorSpace()
|
|
108
|
-
})
|
|
109
|
-
}
|
|
96
|
+
if (data.libassMemoryLimit > 0 || data.libassGlyphLimit > 0) {
|
|
97
|
+
this._wasm.setMemoryLimits(data.libassGlyphLimit || 0, data.libassMemoryLimit || 0)
|
|
98
|
+
}
|
|
99
|
+
this._checkColorSpace()
|
|
110
100
|
|
|
111
|
-
|
|
112
|
-
return this._ready
|
|
101
|
+
return this
|
|
113
102
|
}
|
|
114
103
|
|
|
115
104
|
// this passes a string of track data to libass, be it styles, events etc, which it then processes and adds to the track
|
|
@@ -119,20 +108,15 @@ export class ASSRenderer {
|
|
|
119
108
|
}
|
|
120
109
|
|
|
121
110
|
createEvent (event: ASSEvent) {
|
|
122
|
-
|
|
111
|
+
this._wasm.createEvent(event)
|
|
123
112
|
}
|
|
124
113
|
|
|
125
|
-
getEvents () {
|
|
126
|
-
|
|
127
|
-
for (let i = 0; i < this._wasm.getEventCount(); i++) {
|
|
128
|
-
const { Start, Duration, ReadOrder, Layer, Style, MarginL, MarginR, MarginV, Name, Text, Effect } = this._wasm.getEvent(i)!
|
|
129
|
-
events.push({ Start, Duration, ReadOrder, Layer, Style, MarginL, MarginR, MarginV, Name, Text, Effect })
|
|
130
|
-
}
|
|
131
|
-
return events
|
|
114
|
+
getEvents (): Array<Partial<ASSEvent>> {
|
|
115
|
+
return this._wasm.getEvents()
|
|
132
116
|
}
|
|
133
117
|
|
|
134
118
|
setEvent (event: ASSEvent, index: number) {
|
|
135
|
-
|
|
119
|
+
this._wasm.setEvent(index, event)
|
|
136
120
|
}
|
|
137
121
|
|
|
138
122
|
removeEvent (index: number) {
|
|
@@ -140,24 +124,15 @@ export class ASSRenderer {
|
|
|
140
124
|
}
|
|
141
125
|
|
|
142
126
|
createStyle (style: ASSStyle) {
|
|
143
|
-
|
|
144
|
-
_applyKeys(style, alloc)
|
|
145
|
-
return alloc
|
|
127
|
+
this._wasm.createStyle(style)
|
|
146
128
|
}
|
|
147
129
|
|
|
148
|
-
getStyles () {
|
|
149
|
-
|
|
150
|
-
for (let i = 0; i < this._wasm.getStyleCount(); i++) {
|
|
151
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
152
|
-
const { Name, FontName, FontSize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding, treat_fontname_as_pattern, Blur, Justify } = this._wasm.getStyle(i)!
|
|
153
|
-
|
|
154
|
-
styles.push({ Name, FontName, FontSize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding, treat_fontname_as_pattern, Blur, Justify })
|
|
155
|
-
}
|
|
156
|
-
return styles
|
|
130
|
+
getStyles (): ASSStyle[] {
|
|
131
|
+
return this._wasm.getStyles()
|
|
157
132
|
}
|
|
158
133
|
|
|
159
134
|
setStyle (style: ASSStyle, index: number) {
|
|
160
|
-
|
|
135
|
+
this._wasm.setStyle(index, style)
|
|
161
136
|
}
|
|
162
137
|
|
|
163
138
|
removeStyle (index: number) {
|
|
@@ -165,7 +140,7 @@ export class ASSRenderer {
|
|
|
165
140
|
}
|
|
166
141
|
|
|
167
142
|
styleOverride (style: ASSStyle) {
|
|
168
|
-
this._wasm.styleOverride(
|
|
143
|
+
this._wasm.styleOverride(style)
|
|
169
144
|
}
|
|
170
145
|
|
|
171
146
|
disableStyleOverride () {
|
|
@@ -191,7 +166,7 @@ export class ASSRenderer {
|
|
|
191
166
|
this._gpurender.setColorMatrix(this._subtitleColorSpace, this._videoColorSpace)
|
|
192
167
|
}
|
|
193
168
|
|
|
194
|
-
_defaultFont
|
|
169
|
+
_defaultFont!: string
|
|
195
170
|
setDefaultFont (fontName: string) {
|
|
196
171
|
this._defaultFont = fontName.trim().toLowerCase()
|
|
197
172
|
this._wasm.setDefaultFont(this._defaultFont)
|
|
@@ -206,7 +181,7 @@ export class ASSRenderer {
|
|
|
206
181
|
}
|
|
207
182
|
|
|
208
183
|
async addFonts (fontOrURLs: Array<Uint8Array | string>) {
|
|
209
|
-
if (!fontOrURLs.length) return
|
|
184
|
+
if (!fontOrURLs.length) return false
|
|
210
185
|
const strings: string[] = []
|
|
211
186
|
const uint8s: Uint8Array[] = []
|
|
212
187
|
|
|
@@ -221,7 +196,7 @@ export class ASSRenderer {
|
|
|
221
196
|
|
|
222
197
|
// this isn't batched like uint8s because software like jellyfin exists, which loads 50+ fonts over the network which takes time...
|
|
223
198
|
// is connection exhaustion a concern here?
|
|
224
|
-
return await Promise.allSettled(strings.map(url => this._asyncWrite(url)))
|
|
199
|
+
return !!await Promise.allSettled(strings.map(url => this._asyncWrite(url)))
|
|
225
200
|
}
|
|
226
201
|
|
|
227
202
|
// we don't want to run _findAvailableFont before initial fonts are loaded
|
|
@@ -230,9 +205,10 @@ export class ASSRenderer {
|
|
|
230
205
|
async _loadInitialFonts (fontOrURLs: Array<Uint8Array | string>) {
|
|
231
206
|
await this.addFonts(fontOrURLs)
|
|
232
207
|
this._loadedInitialFonts = true
|
|
208
|
+
this._wasm.reloadFonts()
|
|
233
209
|
}
|
|
234
210
|
|
|
235
|
-
_getFont
|
|
211
|
+
_getFont!: (font: string, weight: WeightValue) => Promise<Uint8Array<ArrayBuffer> | undefined>
|
|
236
212
|
_availableFonts: Record<string, Uint8Array | string> = {}
|
|
237
213
|
_checkedFonts = new Set<string>()
|
|
238
214
|
async _findAvailableFont (fontName: string, weight?: WeightValue) {
|
|
@@ -265,7 +241,7 @@ export class ASSRenderer {
|
|
|
265
241
|
}
|
|
266
242
|
}
|
|
267
243
|
|
|
268
|
-
queryFonts
|
|
244
|
+
queryFonts!: 'local' | 'localandremote' | false
|
|
269
245
|
async _queryLocalFont (fontName: string, weight: WeightValue) {
|
|
270
246
|
if (!this.queryFonts) return
|
|
271
247
|
return await this._getFont(fontName, weight)
|
|
@@ -302,7 +278,6 @@ export class ASSRenderer {
|
|
|
302
278
|
}
|
|
303
279
|
|
|
304
280
|
async [finalizer] () {
|
|
305
|
-
await this._ready
|
|
306
281
|
this._wasm.quitLibrary()
|
|
307
282
|
this._gpurender.destroy()
|
|
308
283
|
// @ts-expect-error force GC
|
|
@@ -313,26 +288,10 @@ export class ASSRenderer {
|
|
|
313
288
|
}
|
|
314
289
|
|
|
315
290
|
_draw (time: number, repaint = false) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const bitmaps: ASSImage[] = []
|
|
322
|
-
|
|
323
|
-
for (let image = result, i = 0; i < this._wasm.count; image = image.next!, ++i) {
|
|
324
|
-
// @ts-expect-error internal emsc types
|
|
325
|
-
bitmaps.push({
|
|
326
|
-
bitmap: image.bitmap,
|
|
327
|
-
color: image.color,
|
|
328
|
-
dst_x: image.dst_x,
|
|
329
|
-
dst_y: image.dst_y,
|
|
330
|
-
h: image.h,
|
|
331
|
-
stride: image.stride,
|
|
332
|
-
w: image.w
|
|
333
|
-
})
|
|
334
|
-
}
|
|
335
|
-
this._gpurender.render(bitmaps, self.HEAPU8RAW)
|
|
291
|
+
const images = this._wasm.rawRender(time, Number(repaint)) as ASSImage[] | null
|
|
292
|
+
if (!images) return
|
|
293
|
+
|
|
294
|
+
this._gpurender.render(images, self.HEAPU8RAW)
|
|
336
295
|
}
|
|
337
296
|
|
|
338
297
|
_setColorSpace (videoColorSpace: 'RGB' | 'BT709' | 'BT601') {
|