libbitsub 1.10.2 → 1.12.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 +296 -49
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/integrations/hlsjs.d.ts +45 -0
- package/dist/integrations/hlsjs.d.ts.map +1 -0
- package/dist/integrations/hlsjs.js +121 -0
- package/dist/integrations/hlsjs.js.map +1 -0
- package/dist/integrations/index.d.ts +11 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/index.js +11 -0
- package/dist/integrations/index.js.map +1 -0
- package/dist/integrations/react.d.ts +55 -0
- package/dist/integrations/react.d.ts.map +1 -0
- package/dist/integrations/react.js +133 -0
- package/dist/integrations/react.js.map +1 -0
- package/dist/integrations/shaka.d.ts +38 -0
- package/dist/integrations/shaka.d.ts.map +1 -0
- package/dist/integrations/shaka.js +71 -0
- package/dist/integrations/shaka.js.map +1 -0
- package/dist/integrations/shared.d.ts +41 -0
- package/dist/integrations/shared.d.ts.map +1 -0
- package/dist/integrations/shared.js +123 -0
- package/dist/integrations/shared.js.map +1 -0
- package/dist/integrations/videojs.d.ts +85 -0
- package/dist/integrations/videojs.d.ts.map +1 -0
- package/dist/integrations/videojs.js +111 -0
- package/dist/integrations/videojs.js.map +1 -0
- package/dist/ts/capabilities.d.ts +8 -0
- package/dist/ts/capabilities.d.ts.map +1 -0
- package/dist/ts/capabilities.js +105 -0
- package/dist/ts/capabilities.js.map +1 -0
- package/dist/ts/diagnostics.d.ts.map +1 -1
- package/dist/ts/diagnostics.js.map +1 -1
- package/dist/ts/frame-export.d.ts.map +1 -1
- package/dist/ts/frame-export.js +4 -4
- package/dist/ts/frame-export.js.map +1 -1
- package/dist/ts/parsers.d.ts +46 -8
- package/dist/ts/parsers.d.ts.map +1 -1
- package/dist/ts/parsers.js +305 -14
- package/dist/ts/parsers.js.map +1 -1
- package/dist/ts/range-loader.d.ts +31 -0
- package/dist/ts/range-loader.d.ts.map +1 -0
- package/dist/ts/range-loader.js +220 -0
- package/dist/ts/range-loader.js.map +1 -0
- package/dist/ts/renderers.d.ts +140 -8
- package/dist/ts/renderers.d.ts.map +1 -1
- package/dist/ts/renderers.js +1773 -287
- package/dist/ts/renderers.js.map +1 -1
- package/dist/ts/types.d.ts +210 -7
- package/dist/ts/types.d.ts.map +1 -1
- package/dist/ts/utils.d.ts.map +1 -1
- package/dist/ts/utils.js +98 -2
- package/dist/ts/utils.js.map +1 -1
- package/dist/ts/video-frame-scheduler.d.ts +35 -0
- package/dist/ts/video-frame-scheduler.d.ts.map +1 -0
- package/dist/ts/video-frame-scheduler.js +98 -0
- package/dist/ts/video-frame-scheduler.js.map +1 -0
- package/dist/ts/wasm.d.ts +2 -0
- package/dist/ts/wasm.d.ts.map +1 -1
- package/dist/ts/wasm.js +12 -0
- package/dist/ts/wasm.js.map +1 -1
- package/dist/ts/webgl2-renderer.d.ts +9 -0
- package/dist/ts/webgl2-renderer.d.ts.map +1 -1
- package/dist/ts/webgl2-renderer.js +34 -0
- package/dist/ts/webgl2-renderer.js.map +1 -1
- package/dist/ts/webgpu-renderer.d.ts +9 -0
- package/dist/ts/webgpu-renderer.d.ts.map +1 -1
- package/dist/ts/webgpu-renderer.js +70 -2
- package/dist/ts/webgpu-renderer.js.map +1 -1
- package/dist/ts/worker.d.ts +11 -0
- package/dist/ts/worker.d.ts.map +1 -1
- package/dist/ts/worker.js +620 -158
- package/dist/ts/worker.js.map +1 -1
- package/dist/wrapper.d.ts +6 -3
- package/dist/wrapper.d.ts.map +1 -1
- package/dist/wrapper.js +5 -2
- package/dist/wrapper.js.map +1 -1
- package/examples/README.md +38 -0
- package/examples/hlsjs/README.md +53 -0
- package/examples/react/README.md +60 -0
- package/examples/shaka/README.md +61 -0
- package/examples/videojs/README.md +55 -0
- package/package.json +66 -8
- package/pkg/README.md +296 -49
- package/pkg/libbitsub.d.ts +65 -1
- package/pkg/libbitsub.js +228 -3
- package/pkg/libbitsub_bg.wasm +0 -0
- package/pkg/libbitsub_bg.wasm.d.ts +28 -0
- package/pkg/package.json +4 -4
- package/src/integrations/hlsjs.ts +154 -0
- package/src/integrations/index.ts +36 -0
- package/src/integrations/react.tsx +176 -0
- package/src/integrations/shaka.ts +92 -0
- package/src/integrations/shared.ts +171 -0
- package/src/integrations/videojs.ts +200 -0
- package/src/wrapper.ts +34 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# libbit(map)sub
|
|
2
2
|
|
|
3
|
-
High-performance WASM renderer for graphical subtitles (PGS, VobSub, and MKS-embedded VobSub), written in Rust.
|
|
3
|
+
High-performance WASM renderer for graphical subtitles (PGS, VobSub, DVB-SUB, and MKS-embedded VobSub), written in Rust.
|
|
4
4
|
|
|
5
5
|
Started as a fork of Arcus92's [libpgs-js](https://github.com/Arcus92/libpgs-js), this project was reworked for higher performance and broader format support. It keeps the familiar high-level PGS-oriented API while adding a lower-level parser surface, VobSub support, GPU backends, and worker-backed rendering.
|
|
6
6
|
|
|
@@ -8,9 +8,11 @@ Started as a fork of Arcus92's [libpgs-js](https://github.com/Arcus92/libpgs-js)
|
|
|
8
8
|
|
|
9
9
|
- PGS (Blu-ray) subtitle parsing and rendering
|
|
10
10
|
- VobSub (DVD) subtitle parsing and rendering
|
|
11
|
+
- DVB-SUB (ETSI EN 300 743) parsing and rendering via PES/ES and `"DV"` PTS-framed dumps
|
|
11
12
|
- Matroska `.mks` extraction for embedded `S_VOBSUB` tracks
|
|
12
13
|
- WebGPU, WebGL2, and Canvas2D rendering with automatic fallback
|
|
13
14
|
- Worker-backed parsing/rendering for large subtitle files
|
|
15
|
+
- HTTP Range / streaming loads for large `.sup`, `.sub`, `.idx`, and `.mks` assets (progressive indexing where feasible)
|
|
14
16
|
- Rich layout controls: scale, aspect mode, horizontal/vertical offsets, alignment, bottom padding, safe area, opacity
|
|
15
17
|
- Cue metadata and parser introspection APIs
|
|
16
18
|
- Rendered-frame export helpers for ImageData, ImageBitmap, Blob, and custom canvas targets
|
|
@@ -18,6 +20,7 @@ Started as a fork of Arcus92's [libpgs-js](https://github.com/Arcus92/libpgs-js)
|
|
|
18
20
|
- Automatic format detection and unified loading helpers
|
|
19
21
|
- First-class diagnostics with structured error codes, warning hooks, and render/cache snapshots
|
|
20
22
|
- TypeScript support with exported event and metadata types
|
|
23
|
+
- Optional player integrations for Video.js, Shaka Player, hls.js, and React (core stays dependency-free)
|
|
21
24
|
|
|
22
25
|
## Showcase
|
|
23
26
|
|
|
@@ -67,11 +70,11 @@ deno add jsr:@altq/libbitsub
|
|
|
67
70
|
|
|
68
71
|
In most bundler-based projects, no manual worker setup is required. `libbitsub` now resolves the WASM asset relative to the package module URL, so bundlers such as Vite, webpack, and Rollup can emit the asset automatically.
|
|
69
72
|
|
|
70
|
-
If your app serves package files in a way that does not expose that emitted WASM asset to the browser, you can still provide the legacy public fallback by copying the WASM file to `/libbitsub
|
|
73
|
+
If your app serves package files in a way that does not expose that emitted WASM asset to the browser, you can still provide the legacy public fallback by copying the WASM file and its JS glue to `/libbitsub/`:
|
|
71
74
|
|
|
72
75
|
```bash
|
|
73
76
|
mkdir -p public/libbitsub
|
|
74
|
-
cp node_modules/libbitsub/pkg/libbitsub_bg.wasm public/libbitsub/
|
|
77
|
+
cp node_modules/libbitsub/pkg/libbitsub_bg.wasm node_modules/libbitsub/pkg/libbitsub.js public/libbitsub/
|
|
75
78
|
```
|
|
76
79
|
|
|
77
80
|
The worker is still created inline. `workerUrl` remains in the option type only for compatibility and does not change runtime behavior.
|
|
@@ -110,6 +113,129 @@ const parser = new PgsParser()
|
|
|
110
113
|
|
|
111
114
|
Calling `initWasm()` multiple times is safe (it deduplicates).
|
|
112
115
|
|
|
116
|
+
### Worker prewarm (TV / players)
|
|
117
|
+
|
|
118
|
+
On devices where the first subtitle track switch should not pay worker + WASM startup cost (for example TV apps), prewarm the shared parsing worker during app startup:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import { warmup, ready, PgsRenderer } from 'libbitsub'
|
|
122
|
+
|
|
123
|
+
// Fire-and-forget at app boot (safe to call multiple times).
|
|
124
|
+
void warmup()
|
|
125
|
+
|
|
126
|
+
// Before the user changes tracks, ensure the worker is ready.
|
|
127
|
+
await ready()
|
|
128
|
+
|
|
129
|
+
const renderer = new PgsRenderer({ video: videoElement, subContent: trackBytes })
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`warmup()` and `ready()` share a single worker-init promise with renderer creation. The shared worker is only published after in-worker WASM initialization succeeds. When Web Workers are unavailable, both resolve immediately and renderers use the main thread.
|
|
133
|
+
|
|
134
|
+
### Range / streaming loads (TV / slow networks)
|
|
135
|
+
|
|
136
|
+
URL-based loads (`subUrl` / `idxUrl`) use progressive fetch by default:
|
|
137
|
+
|
|
138
|
+
- Probe HTTP Range support and, for large assets, download with Range chunks when the origin allows it
|
|
139
|
+
- Stream the response body otherwise and report `load-progress` events
|
|
140
|
+
- **PGS (`.sup`)**: feed chunks into the parser as they arrive so cues can be indexed before the full file finishes
|
|
141
|
+
- **VobSub (`.idx` + `.sub`)**: parse the small `.idx` first for timestamps, then stream/Range-download the `.sub` body and attach packets
|
|
142
|
+
- **MKS**: stream/Range-download the container first (Matroska extraction still needs the assembled payload), then parse
|
|
143
|
+
- **In-memory** `subContent` / `idxContent` remains the simple full-buffer path
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { PgsRenderer } from 'libbitsub'
|
|
147
|
+
|
|
148
|
+
const renderer = new PgsRenderer({
|
|
149
|
+
video: videoElement,
|
|
150
|
+
subUrl: '/subtitles/movie.sup',
|
|
151
|
+
// streamingLoad: true, // default
|
|
152
|
+
// rangeRequests: true, // default
|
|
153
|
+
onEvent: (event) => {
|
|
154
|
+
if (event.type === 'load-progress') {
|
|
155
|
+
console.log(event.strategy, event.loadedBytes, event.totalBytes, event.indexedCues)
|
|
156
|
+
}
|
|
157
|
+
if (event.type === 'indexed') {
|
|
158
|
+
console.log('cues ready', event.metadata.cueCount, event.partial ? '(partial)' : '(final)')
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Disable progressive behavior when you want a single blocking GET:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
new PgsRenderer({ video, subUrl, streamingLoad: false, rangeRequests: false })
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Low-level helpers are also exported: `probeRangeSupport()`, `fetchSubtitleAsset()`, and `fetchSubtitleText()`.
|
|
171
|
+
|
|
172
|
+
## Player integrations
|
|
173
|
+
|
|
174
|
+
Optional adapters ship as **subpath exports**. They wrap the high-level renderers for common players while keeping the core package free of player/React dependencies (peer deps are optional and only needed when you import that adapter).
|
|
175
|
+
|
|
176
|
+
| Import | Adapter | Optional peer |
|
|
177
|
+
| ------------------------ | ---------------------------------------- | ------------------- |
|
|
178
|
+
| `libbitsub/videojs` | Video.js plugin (`registerBitSubPlugin`) | `video.js` >= 7 |
|
|
179
|
+
| `libbitsub/shaka` | `attachBitSubToShaka(player, options)` | `shaka-player` >= 4 |
|
|
180
|
+
| `libbitsub/hlsjs` | `attachBitSubToHls(hls, options)` | `hls.js` >= 1 |
|
|
181
|
+
| `libbitsub/react` | `useBitSub` / `BitSubOverlay` | `react` >= 18 |
|
|
182
|
+
| `libbitsub/integrations` | Shared `attachBitSub` controller | — |
|
|
183
|
+
|
|
184
|
+
Copy-paste recipes live under [`examples/`](./examples).
|
|
185
|
+
|
|
186
|
+
### Video.js
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import videojs from 'video.js'
|
|
190
|
+
import { registerBitSubPlugin } from 'libbitsub/videojs'
|
|
191
|
+
|
|
192
|
+
registerBitSubPlugin(videojs)
|
|
193
|
+
const player = videojs('my-video')
|
|
194
|
+
const bitsub = player.bitsub({ subUrl: '/subs/movie.sup' })
|
|
195
|
+
bitsub.load({ subUrl: '/subs/other.sup' })
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Shaka Player
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import { attachBitSubToShaka } from 'libbitsub/shaka'
|
|
202
|
+
|
|
203
|
+
const bitsub = attachBitSubToShaka(player, { subUrl: '/subs/movie.sup' })
|
|
204
|
+
// later
|
|
205
|
+
bitsub.dispose()
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### hls.js
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import Hls from 'hls.js'
|
|
212
|
+
import { attachBitSubToHls } from 'libbitsub/hlsjs'
|
|
213
|
+
|
|
214
|
+
const hls = new Hls()
|
|
215
|
+
hls.loadSource(url)
|
|
216
|
+
hls.attachMedia(video)
|
|
217
|
+
const bitsub = attachBitSubToHls(hls, { subUrl: '/subs/movie.sup' })
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### React
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
import { useRef } from 'react'
|
|
224
|
+
import { useBitSub } from 'libbitsub/react'
|
|
225
|
+
|
|
226
|
+
function Player({ src, subUrl }: { src: string; subUrl: string }) {
|
|
227
|
+
const videoRef = useRef<HTMLVideoElement>(null)
|
|
228
|
+
useBitSub(videoRef, { subUrl })
|
|
229
|
+
return (
|
|
230
|
+
<div style={{ position: 'relative' }}>
|
|
231
|
+
<video ref={videoRef} src={src} controls playsInline />
|
|
232
|
+
</div>
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Bitmap PGS/VobSub/MKS tracks are external canvas overlays, not native HTML/TextTrack entries. Prefer deep imports so unused adapters stay out of your bundle.
|
|
238
|
+
|
|
113
239
|
## High-level video renderers
|
|
114
240
|
|
|
115
241
|
The high-level API manages subtitle loading, canvas overlay creation, playback sync, resize handling, worker usage, and renderer fallback.
|
|
@@ -131,6 +257,7 @@ const renderer = new PgsRenderer({
|
|
|
131
257
|
},
|
|
132
258
|
cacheLimit: 32,
|
|
133
259
|
prefetchWindow: { before: 1, after: 2 },
|
|
260
|
+
frameAwareSync: true,
|
|
134
261
|
onWarning: (warning) => {
|
|
135
262
|
console.warn(warning.code, warning.message, warning.details)
|
|
136
263
|
},
|
|
@@ -144,6 +271,33 @@ const renderer = new PgsRenderer({
|
|
|
144
271
|
renderer.dispose()
|
|
145
272
|
```
|
|
146
273
|
|
|
274
|
+
Mount into a fullscreen shell or Shadow DOM root, reuse a player-owned canvas,
|
|
275
|
+
cap high-DPI backing-store cost, or bypass automatic backend selection:
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
const renderer = new PgsRenderer({
|
|
279
|
+
video: videoElement,
|
|
280
|
+
subUrl: '/subtitles/movie.sup',
|
|
281
|
+
container: shadowRoot, // HTMLElement or ShadowRoot; defaults to video.parentElement
|
|
282
|
+
canvas: playerOverlayCanvas, // optional; remains mounted after dispose()
|
|
283
|
+
devicePixelRatioCap: 2,
|
|
284
|
+
backend: 'webgl2' // 'auto' | 'webgpu' | 'webgl2' | 'worker-offscreen' | 'canvas2d'
|
|
285
|
+
})
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
An explicitly requested GPU or worker backend falls back to Canvas2D if it cannot
|
|
289
|
+
initialize. A supplied `container` takes precedence over the canvas's current parent;
|
|
290
|
+
without one, an already-mounted caller canvas stays in its existing host. Automatic
|
|
291
|
+
selection does not transfer a caller-owned canvas to a worker; request
|
|
292
|
+
`backend: 'worker-offscreen'` explicitly to allow that ownership transfer.
|
|
293
|
+
|
|
294
|
+
Frame-aware synchronization is enabled by default. On browsers with
|
|
295
|
+
`requestVideoFrameCallback()`, cue lookup uses the `mediaTime` of the frame sent
|
|
296
|
+
to the compositor instead of polling `video.currentTime`. Older browsers fall
|
|
297
|
+
back to `requestAnimationFrame()` automatically; set `frameAwareSync: false` to
|
|
298
|
+
force that compatibility path. The active path is available as
|
|
299
|
+
`renderer.getSynchronizationMode()` and as `getStats().syncMode`.
|
|
300
|
+
|
|
147
301
|
### VobSub renderer
|
|
148
302
|
|
|
149
303
|
```ts
|
|
@@ -165,6 +319,45 @@ renderer.setDebandThreshold(64)
|
|
|
165
319
|
renderer.setDebandRange(15)
|
|
166
320
|
```
|
|
167
321
|
|
|
322
|
+
### DVB renderer
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
import { DvbRenderer } from 'libbitsub'
|
|
326
|
+
|
|
327
|
+
const renderer = new DvbRenderer({
|
|
328
|
+
video: videoElement,
|
|
329
|
+
subUrl: '/subtitles/track.dvb'
|
|
330
|
+
})
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
DVB dumps use libbitsub framing:
|
|
334
|
+
|
|
335
|
+
```
|
|
336
|
+
"DV" | pts_90k_be_u32 | payload_len_be_u32 | payload…
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`payload` is a PES data field (`0x20 0x00 …`) or raw segments (`sync_byte 0x0F`). Concatenated MPEG PES packets (`00 00 01 BD`) with PTS are also accepted.
|
|
340
|
+
|
|
341
|
+
The DVB decoder renders bitmap object coding method 0. Character-string and reserved object coding methods are ignored.
|
|
342
|
+
|
|
343
|
+
### Live / push streams
|
|
344
|
+
|
|
345
|
+
PGS and DVB renderers can start without a URL or in-memory subtitle file. Push transport or demuxer chunks as they arrive; calls are processed in order even when they are made before renderer initialization completes.
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
import { DvbRenderer } from 'libbitsub'
|
|
349
|
+
|
|
350
|
+
const renderer = new DvbRenderer({ video: videoElement })
|
|
351
|
+
|
|
352
|
+
const added = await renderer.append(dvbPesChunk) // newly indexed cues
|
|
353
|
+
const total = await renderer.flush() // finalize trailing input; total indexed cues
|
|
354
|
+
|
|
355
|
+
await renderer.reset() // clear cues/caches/display, then reuse the same renderer
|
|
356
|
+
await renderer.append(nextChannelChunk)
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
`append()` accepts `Uint8Array` or `ArrayBuffer` without detaching the caller's buffer. `flush()` discards incomplete trailing bytes; later appends are still accepted. `reset()` keeps the canvas, worker session, render loop, and configuration alive while clearing the stream state. VobSub does not expose the push API because it depends on its `.idx`/container index.
|
|
360
|
+
|
|
168
361
|
### Automatic format detection
|
|
169
362
|
|
|
170
363
|
```ts
|
|
@@ -177,7 +370,7 @@ const renderer = createAutoSubtitleRenderer({
|
|
|
177
370
|
})
|
|
178
371
|
```
|
|
179
372
|
|
|
180
|
-
Automatic detection uses file hints when available and otherwise inspects the binary payload. `.mks` sources are treated as VobSub only when they contain an embedded `S_VOBSUB` track. If the format cannot be identified confidently, it throws instead of silently forcing a parser.
|
|
373
|
+
Automatic detection uses file hints when available and otherwise inspects the binary payload. `.idx` / `idxContent` still means VobSub. Bare `.sub` is content-probed for DVB before VobSub. `.mks` sources are treated as VobSub only when they contain an embedded `S_VOBSUB` track. If the format cannot be identified confidently, it throws instead of silently forcing a parser.
|
|
181
374
|
|
|
182
375
|
## Layout controls
|
|
183
376
|
|
|
@@ -207,16 +400,16 @@ renderer.resetDisplaySettings()
|
|
|
207
400
|
|
|
208
401
|
`SubtitleDisplaySettings`:
|
|
209
402
|
|
|
210
|
-
| Field
|
|
211
|
-
|
|
|
212
|
-
| `scale`
|
|
213
|
-
| `aspectMode`
|
|
214
|
-
| `verticalOffset`
|
|
215
|
-
| `horizontalOffset` | number
|
|
216
|
-
| `horizontalAlign`
|
|
217
|
-
| `bottomPadding`
|
|
218
|
-
| `safeArea`
|
|
219
|
-
| `opacity`
|
|
403
|
+
| Field | Type | Range / values | Meaning |
|
|
404
|
+
| ------------------ | ----------------------------------- | -------------- | -------------------------------------------------------------- |
|
|
405
|
+
| `scale` | number | `0.1` to `3.0` | Overall subtitle scale |
|
|
406
|
+
| `aspectMode` | `'stretch' \| 'contain' \| 'cover'` | fixed set | How subtitle screen coordinates map into the visible video box |
|
|
407
|
+
| `verticalOffset` | number | `-50` to `50` | Vertical movement as percent of video height |
|
|
408
|
+
| `horizontalOffset` | number | `-50` to `50` | Horizontal movement as percent of video width |
|
|
409
|
+
| `horizontalAlign` | `'left' \| 'center' \| 'right'` | fixed set | Anchor used when scaling subtitle groups |
|
|
410
|
+
| `bottomPadding` | number | `0` to `50` | Extra padding from the bottom edge |
|
|
411
|
+
| `safeArea` | number | `0` to `25` | Clamp subtitles inside a video-safe area |
|
|
412
|
+
| `opacity` | number | `0.0` to `1.0` | Global subtitle opacity |
|
|
220
413
|
|
|
221
414
|
## Metadata and introspection
|
|
222
415
|
|
|
@@ -291,14 +484,7 @@ Like `UnifiedSubtitleParser.loadAuto()`, this is a low-level in-memory API: pass
|
|
|
291
484
|
Low-level parser output can be flattened into a single exportable frame for previews, editors, snapshots, fixture generation, or visual diffing.
|
|
292
485
|
|
|
293
486
|
```ts
|
|
294
|
-
import {
|
|
295
|
-
PgsParser,
|
|
296
|
-
initWasm,
|
|
297
|
-
renderFrameData,
|
|
298
|
-
toBlob,
|
|
299
|
-
toCanvas,
|
|
300
|
-
toImageBitmap
|
|
301
|
-
} from 'libbitsub'
|
|
487
|
+
import { PgsParser, initWasm, renderFrameData, toBlob, toCanvas, toImageBitmap } from 'libbitsub'
|
|
302
488
|
|
|
303
489
|
await initWasm()
|
|
304
490
|
|
|
@@ -385,7 +571,7 @@ Structured diagnostic error codes currently include:
|
|
|
385
571
|
- `WORKER_FALLBACK`
|
|
386
572
|
- `UNKNOWN`
|
|
387
573
|
|
|
388
|
-
Warnings use a smaller code set focused on non-fatal conditions such as malformed bitmap buffers, worker fallback, and missing PGS palettes during render.
|
|
574
|
+
Warnings use a smaller code set focused on non-fatal conditions such as malformed bitmap buffers, worker fallback, progressive/Range fallback (`RANGE_FALLBACK`), and missing PGS palettes during render.
|
|
389
575
|
|
|
390
576
|
## MKS security and corruption checks
|
|
391
577
|
|
|
@@ -415,6 +601,8 @@ const renderer = new PgsRenderer({
|
|
|
415
601
|
onEvent: (event) => {
|
|
416
602
|
switch (event.type) {
|
|
417
603
|
case 'loading':
|
|
604
|
+
case 'load-progress':
|
|
605
|
+
case 'indexed':
|
|
418
606
|
case 'loaded':
|
|
419
607
|
case 'error':
|
|
420
608
|
case 'warning':
|
|
@@ -482,17 +670,17 @@ renderer.dispose()
|
|
|
482
670
|
|
|
483
671
|
Emitted events:
|
|
484
672
|
|
|
485
|
-
| Event
|
|
486
|
-
|
|
|
487
|
-
| `loading`
|
|
488
|
-
| `loaded`
|
|
489
|
-
| `error`
|
|
490
|
-
| `warning`
|
|
491
|
-
| `renderer-change` | active backend: `webgpu`, `webgl2`, or `canvas2d`
|
|
492
|
-
| `worker-state`
|
|
493
|
-
| `cache-change`
|
|
494
|
-
| `cue-change`
|
|
495
|
-
| `stats`
|
|
673
|
+
| Event | Payload |
|
|
674
|
+
| ----------------- | --------------------------------------------------------------------------------- |
|
|
675
|
+
| `loading` | subtitle format |
|
|
676
|
+
| `loaded` | subtitle format and parser metadata |
|
|
677
|
+
| `error` | subtitle format and `SubtitleDiagnosticErrorLike` |
|
|
678
|
+
| `warning` | `SubtitleDiagnosticWarning` |
|
|
679
|
+
| `renderer-change` | active backend: `webgpu`, `webgl2`, `worker-offscreen`, or `canvas2d` |
|
|
680
|
+
| `worker-state` | whether worker mode is enabled, ready, fallback status, and the active session ID |
|
|
681
|
+
| `cache-change` | cached frame count, pending renders, and configured cache limit |
|
|
682
|
+
| `cue-change` | current cue metadata or `null` when nothing is displayed |
|
|
683
|
+
| `stats` | periodic renderer stats snapshot |
|
|
496
684
|
|
|
497
685
|
## Performance stats
|
|
498
686
|
|
|
@@ -514,6 +702,7 @@ const stats = renderer.getStats()
|
|
|
514
702
|
- `pendingRenders`
|
|
515
703
|
- `totalEntries`
|
|
516
704
|
- `currentIndex`
|
|
705
|
+
- `syncMode`
|
|
517
706
|
|
|
518
707
|
`getCacheStats()` adds worker/session state for the current renderer cache, while `getLastRenderInfo()` exposes the most recent render outcome with a status of `rendered`, `cleared`, `pending`, `empty`, or `failed`.
|
|
519
708
|
|
|
@@ -563,23 +752,50 @@ const parser = new UnifiedSubtitleParser({
|
|
|
563
752
|
parser.loadAuto({ data: subtitleBytes, fileName: 'track.sup' })
|
|
564
753
|
```
|
|
565
754
|
|
|
566
|
-
## GPU backends
|
|
755
|
+
## GPU / present backends
|
|
567
756
|
|
|
568
757
|
libbitsub prefers:
|
|
569
758
|
|
|
570
|
-
1. WebGPU
|
|
571
|
-
2. WebGL2
|
|
572
|
-
3. Canvas2D
|
|
759
|
+
1. WebGPU (main-thread present)
|
|
760
|
+
2. WebGL2 (main-thread present)
|
|
761
|
+
3. Worker OffscreenCanvas (decode + Canvas2D present off the UI thread)
|
|
762
|
+
4. Canvas2D (main-thread fallback for older TVs)
|
|
573
763
|
|
|
574
764
|
```ts
|
|
575
|
-
import { isWebGPUSupported } from 'libbitsub'
|
|
765
|
+
import { getRuntimeCapabilities, isWebGPUSupported } from 'libbitsub'
|
|
576
766
|
|
|
577
767
|
console.log({
|
|
578
|
-
webgpu: isWebGPUSupported()
|
|
768
|
+
webgpu: isWebGPUSupported(),
|
|
769
|
+
capabilities: getRuntimeCapabilities()
|
|
579
770
|
})
|
|
580
771
|
```
|
|
581
772
|
|
|
582
|
-
|
|
773
|
+
When Worker OffscreenCanvas is selected, composition/present moves into the shared worker —
|
|
774
|
+
not only parsing — which reduces UI stalls during subtitle track switches on constrained devices.
|
|
775
|
+
The existing transferable RGBA path remains for main-thread GPU/Canvas2D present.
|
|
776
|
+
|
|
777
|
+
Use `onWebGPUFallback`, `onWebGL2Fallback`, `onEvent`, `onWarning`, or `getRuntimeCapabilities()`
|
|
778
|
+
to observe or explain the active backend path. Set `offscreenRender: false` to force main-thread
|
|
779
|
+
Canvas2D on the software tier.
|
|
780
|
+
|
|
781
|
+
## Compatibility & visual regression
|
|
782
|
+
|
|
783
|
+
A formal suite locks decoder edge cases and backend pixel parity:
|
|
784
|
+
|
|
785
|
+
- Malformed PGS / VobSub / MKS fixtures
|
|
786
|
+
- Palette edge cases and zero-length RLE runs
|
|
787
|
+
- Alternate display sizes (SD → 4K)
|
|
788
|
+
- Slow worker startup / shared init
|
|
789
|
+
- Pixel-level goldens across software, Canvas2D, WebGL2, and WebGPU
|
|
790
|
+
|
|
791
|
+
```bash
|
|
792
|
+
bun run test # Rust core (includes compatibility fixtures)
|
|
793
|
+
bun run test:ts # TypeScript fixtures, goldens, worker startup
|
|
794
|
+
bun run test:visual # Headless Chromium backend parity
|
|
795
|
+
bun run test:all # All of the above
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
Browser/device support matrix (including webOS TV): [docs/COMPATIBILITY.md](./docs/COMPATIBILITY.md).
|
|
583
799
|
|
|
584
800
|
## Notes
|
|
585
801
|
|
|
@@ -594,10 +810,13 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
594
810
|
|
|
595
811
|
- `initWasm(): Promise<void>` initializes the WASM module. Called automatically by high-level renderers and on first import in browser environments. Safe to call multiple times. Only needed explicitly for low-level parser usage.
|
|
596
812
|
- `isWasmInitialized(): boolean` reports whether initialization has completed.
|
|
813
|
+
- `warmup(): Promise<void>` / `ready(): Promise<void>` pre-initialize the shared subtitle worker (including in-worker WASM). Safe to call multiple times; concurrent callers share one init promise. Prefer these in TV/player apps before the first track switch.
|
|
814
|
+
- `isWorkerAvailable(): boolean` / `isWorkerReady(): boolean` report worker support and whether the shared worker has finished initializing.
|
|
597
815
|
- `isWebGPUSupported(): boolean` checks WebGPU support.
|
|
598
|
-
- `detectSubtitleFormat(source: AutoSubtitleSource): 'pgs' | 'vobsub' | null` detects the bitmap subtitle format from file hints or binary data.
|
|
599
|
-
- `createAutoSubtitleRenderer(options: AutoVideoSubtitleOptions): PgsRenderer | VobSubRenderer` creates a high-level renderer after format detection.
|
|
816
|
+
- `detectSubtitleFormat(source: AutoSubtitleSource): 'pgs' | 'vobsub' | 'dvb' | null` detects the bitmap subtitle format from file hints or binary data.
|
|
817
|
+
- `createAutoSubtitleRenderer(options: AutoVideoSubtitleOptions): PgsRenderer | VobSubRenderer | DvbRenderer` creates a high-level renderer after format detection.
|
|
600
818
|
- `openSubtitles(source, options?): Promise<OpenedSubtitles>` initializes WASM, auto-detects the low-level format, and returns a normalized parser handle.
|
|
819
|
+
- `probeRangeSupport(url, options?)` / `fetchSubtitleAsset(url, options?, onChunk?)` / `fetchSubtitleText(url, options?)` perform Range-aware progressive asset downloads for custom loaders.
|
|
601
820
|
- `renderFrameData(frame, options?): SubtitleRenderedFrameData | null` composes a `SubtitleData` frame into exportable pixels.
|
|
602
821
|
- `toCanvas(frame, target?, options?): HTMLCanvasElement | OffscreenCanvas` draws a rendered frame to a new or existing canvas/context.
|
|
603
822
|
- `toImageBitmap(frame, options?): Promise<ImageBitmap>` creates an `ImageBitmap` from a subtitle frame export.
|
|
@@ -605,6 +824,7 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
605
824
|
- `SubtitleDiagnosticError` is the structured error class libbitsub uses for coded diagnostics.
|
|
606
825
|
- `createSubtitleDiagnosticError(...)` and `normalizeSubtitleError(...)` are exported for integrations that want to preserve libbitsub-style error codes.
|
|
607
826
|
- Legacy aliases remain exported: `PGSRenderer`, `VobsubRenderer`, `UnifiedSubtitleRenderer`.
|
|
827
|
+
- Optional integration entry points: `libbitsub/videojs`, `libbitsub/shaka`, `libbitsub/hlsjs`, `libbitsub/react`, `libbitsub/integrations` (see [examples/](./examples) and [references/api.md](./references/api.md)).
|
|
608
828
|
|
|
609
829
|
### High-level renderers
|
|
610
830
|
|
|
@@ -625,21 +845,30 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
625
845
|
- `clearFrameCache(): void` clears the renderer-side and parser-side frame cache.
|
|
626
846
|
- `prefetchRange(startIndex: number, endIndex: number): Promise<void>` prefetches decoded frames for a cue range.
|
|
627
847
|
- `prefetchAroundTime(time: number, before?: number, after?: number): Promise<void>` prefetches around a playback time in seconds.
|
|
848
|
+
- `append(data: Uint8Array | ArrayBuffer): Promise<number>` pushes live bytes and returns newly indexed cues.
|
|
849
|
+
- `flush(): Promise<number>` finalizes trailing input and returns the total cue count.
|
|
850
|
+
- `reset(): Promise<void>` clears live parser, cue, cache, and presentation state for reuse.
|
|
628
851
|
- `dispose(): void` releases DOM, parser, and worker resources.
|
|
629
852
|
|
|
630
853
|
#### `VobSubRenderer`
|
|
631
854
|
|
|
632
|
-
- Supports
|
|
855
|
+
- Supports the common `PgsRenderer` methods above, except `append()`, `flush()`, and `reset()`.
|
|
633
856
|
- `setDebandEnabled(enabled: boolean): void` enables or disables debanding.
|
|
634
857
|
- `setDebandThreshold(threshold: number): void` updates the deband threshold.
|
|
635
858
|
- `setDebandRange(range: number): void` updates the deband sample range.
|
|
636
859
|
- `debandEnabled: boolean` reports whether debanding is enabled.
|
|
637
860
|
|
|
861
|
+
#### `DvbRenderer`
|
|
862
|
+
|
|
863
|
+
- Supports all `PgsRenderer` methods above, including the live push API (no debanding).
|
|
864
|
+
|
|
638
865
|
### Low-level parsers
|
|
639
866
|
|
|
640
867
|
#### `PgsParser`
|
|
641
868
|
|
|
642
|
-
- `load(data: Uint8Array): number` loads PGS data and returns the cue count.
|
|
869
|
+
- `load(data: Uint8Array): number` loads PGS data and returns the cue count (simple in-memory path).
|
|
870
|
+
- `reset(): void` / `feed(data: Uint8Array): number` / `finishFeed(): number` progressive indexing APIs for streamed chunks.
|
|
871
|
+
- `pendingLen: number` incomplete trailing bytes retained between `feed()` calls.
|
|
643
872
|
- `getTimestamps(): Float64Array` returns cue timestamps in milliseconds.
|
|
644
873
|
- `count: number` returns the number of cues.
|
|
645
874
|
- `findIndexAtTimestamp(timeSeconds: number): number` finds the cue index for a playback time in seconds.
|
|
@@ -650,9 +879,18 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
650
879
|
- `clearCache(): void` clears parser-side caches.
|
|
651
880
|
- `dispose(): void` frees parser resources.
|
|
652
881
|
|
|
882
|
+
#### `DvbParser`
|
|
883
|
+
|
|
884
|
+
- Same progressive surface as `PgsParser` for `"DV"`-framed dumps and MPEG PES streams.
|
|
885
|
+
- `load(data: Uint8Array): number` / `feed` / `finishFeed` / `renderAtIndex` / `renderAtTimestamp` / `getMetadata` / `getCueMetadata` / `dispose`.
|
|
886
|
+
- `getEndTimestamps(): Float64Array` returns the page-timeout-aware cue end timestamps in milliseconds.
|
|
887
|
+
|
|
653
888
|
#### `VobSubParserLowLevel`
|
|
654
889
|
|
|
655
|
-
- `loadFromData(idxContent: string, subData: Uint8Array): void` loads IDX and SUB data.
|
|
890
|
+
- `loadFromData(idxContent: string, subData: Uint8Array): void` loads IDX and SUB data (simple in-memory path).
|
|
891
|
+
- `loadFromIdx(idxContent: string): void` indexes timestamps from IDX before packet bytes arrive.
|
|
892
|
+
- `attachSubData(subData: Uint8Array): void` attaches `.sub` packets after an IDX-first load.
|
|
893
|
+
- `hasSubData: boolean` whether packet bytes are currently attached.
|
|
656
894
|
- `loadFromSubOnly(subData: Uint8Array): void` loads SUB-only VobSub data.
|
|
657
895
|
- `getTimestamps(): Float64Array`, `count`, `findIndexAtTimestamp()`, `renderAtIndex()`, `renderAtTimestamp()`, `getMetadata()`, `getCueMetadata()`, `clearCache()`, and `dispose()` behave like `PgsParser`.
|
|
658
896
|
- `setDebandEnabled(enabled: boolean): void`, `setDebandThreshold(threshold: number): void`, `setDebandRange(range: number): void`, and `debandEnabled` control debanding.
|
|
@@ -662,8 +900,9 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
662
900
|
- `loadPgs(data: Uint8Array): number` loads PGS data.
|
|
663
901
|
- `loadVobSub(idxContent: string, subData: Uint8Array): void` loads VobSub from IDX and SUB.
|
|
664
902
|
- `loadVobSubOnly(subData: Uint8Array): void` loads SUB-only VobSub data.
|
|
903
|
+
- `loadDvb(data: Uint8Array): number` loads DVB data.
|
|
665
904
|
- `loadAuto(source: AutoSubtitleSource): SubtitleFormatName` detects and loads a supported bitmap subtitle format.
|
|
666
|
-
- `format: 'pgs' | 'vobsub' | null` returns the active format.
|
|
905
|
+
- `format: 'pgs' | 'vobsub' | 'dvb' | null` returns the active format.
|
|
667
906
|
- `getTimestamps()`, `count`, `findIndexAtTimestamp()`, `renderAtIndex()`, `renderAtTimestamp()`, `getMetadata()`, `getCueMetadata()`, `clearCache()`, and `dispose()` are available as on the format-specific parsers.
|
|
668
907
|
|
|
669
908
|
### Core option and data types
|
|
@@ -673,6 +912,10 @@ WebGL2 and Canvas2D fallback remain automatic. Use `onWebGPUFallback`, `onWebGL2
|
|
|
673
912
|
```ts
|
|
674
913
|
interface VideoSubtitleOptions {
|
|
675
914
|
video: HTMLVideoElement
|
|
915
|
+
container?: HTMLElement | ShadowRoot
|
|
916
|
+
canvas?: HTMLCanvasElement
|
|
917
|
+
devicePixelRatioCap?: number
|
|
918
|
+
backend?: 'auto' | 'webgpu' | 'webgl2' | 'worker-offscreen' | 'canvas2d'
|
|
676
919
|
subUrl?: string
|
|
677
920
|
subContent?: ArrayBuffer
|
|
678
921
|
workerUrl?: string
|
|
@@ -681,12 +924,16 @@ interface VideoSubtitleOptions {
|
|
|
681
924
|
onError?: (error: Error) => void
|
|
682
925
|
onWebGPUFallback?: () => void
|
|
683
926
|
onWebGL2Fallback?: () => void
|
|
927
|
+
offscreenRender?: boolean // default true — Worker OffscreenCanvas on Canvas2D tier
|
|
928
|
+
frameAwareSync?: boolean // default true — sync to presented-frame mediaTime when available
|
|
684
929
|
displaySettings?: Partial<SubtitleDisplaySettings>
|
|
685
930
|
cacheLimit?: number
|
|
686
931
|
prefetchWindow?: {
|
|
687
932
|
before?: number
|
|
688
933
|
after?: number
|
|
689
934
|
}
|
|
935
|
+
streamingLoad?: boolean // default true — progressive URL loads
|
|
936
|
+
rangeRequests?: boolean // default true — use HTTP Range when supported
|
|
690
937
|
onEvent?: (event: SubtitleRendererEvent) => void
|
|
691
938
|
}
|
|
692
939
|
```
|
|
@@ -733,7 +980,7 @@ type SubtitleRendererEvent =
|
|
|
733
980
|
| { type: 'loaded'; format: SubtitleFormatName; metadata: SubtitleParserMetadata }
|
|
734
981
|
| { type: 'error'; format: SubtitleFormatName; error: SubtitleDiagnosticErrorLike }
|
|
735
982
|
| { type: 'warning'; warning: SubtitleDiagnosticWarning }
|
|
736
|
-
| { type: 'renderer-change'; renderer: 'webgpu' | 'webgl2' | 'canvas2d' }
|
|
983
|
+
| { type: 'renderer-change'; renderer: 'webgpu' | 'webgl2' | 'worker-offscreen' | 'canvas2d' }
|
|
737
984
|
| { type: 'worker-state'; enabled: boolean; ready: boolean; sessionId: string | null; fallback?: boolean }
|
|
738
985
|
| { type: 'cache-change'; cachedFrames: number; pendingRenders: number; cacheLimit: number }
|
|
739
986
|
| { type: 'cue-change'; cue: SubtitleCueMetadata | null }
|
|
@@ -766,7 +1013,7 @@ Related diagnostics shapes:
|
|
|
766
1013
|
|
|
767
1014
|
```ts
|
|
768
1015
|
interface SubtitleParserMetadata {
|
|
769
|
-
format: 'pgs' | 'vobsub'
|
|
1016
|
+
format: 'pgs' | 'vobsub' | 'dvb'
|
|
770
1017
|
cueCount: number
|
|
771
1018
|
screenWidth: number
|
|
772
1019
|
screenHeight: number
|
package/dist/index.d.ts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
|
-
export { PgsRenderer, VobSubRenderer, createAutoSubtitleRenderer, type VideoSubtitleOptions, type VideoVobSubOptions, type SubtitleRendererStats } from './wrapper';
|
|
7
|
-
export { PgsParser, VobSubParserLowLevel, UnifiedSubtitleParser, openSubtitles } from './wrapper';
|
|
8
|
-
export { initWasm, isWasmInitialized, isWebGPUSupported, detectSubtitleFormat, renderFrameData, toBlob, toCanvas, toImageBitmap, createSubtitleDiagnosticError, normalizeSubtitleError, SubtitleDiagnosticError, type AutoSubtitleSource, type AutoVideoSubtitleOptions, type OpenedSubtitles, type SubtitleAspectMode, type SubtitleCacheStats, type SubtitleCueBounds, type SubtitleCueMetadata, type SubtitleData, type SubtitleDiagnosticDetailValue, type SubtitleDiagnosticErrorCode, type SubtitleDiagnosticErrorLike, type SubtitleDiagnosticsOptions, type SubtitleDiagnosticWarning, type SubtitleDiagnosticWarningCode, type SubtitleCompositionData, type SubtitleDisplaySettings, type SubtitleFrameCanvasOptions, type SubtitleFrameCanvasTarget, type SubtitleFrameCropMode, type SubtitleFrameRenderOptions, type SubtitleRenderedFrameData, type SubtitleFormatName, type SubtitleHorizontalAlign, type SubtitleLastRenderInfo, type SubtitleParserMetadata, type SubtitleRendererBackend, type SubtitleRendererEvent, type SubtitleRendererStatsSnapshot } from './wrapper';
|
|
6
|
+
export { PgsRenderer, DvbRenderer, VobSubRenderer, createAutoSubtitleRenderer, type VideoSubtitleOptions, type VideoVobSubOptions, type SubtitleRendererStats } from './wrapper';
|
|
7
|
+
export { PgsParser, DvbParser, VobSubParserLowLevel, UnifiedSubtitleParser, openSubtitles } from './wrapper';
|
|
8
|
+
export { initWasm, isWasmInitialized, isWebGPUSupported, isWorkerAvailable, isWorkerReady, warmup, ready, getRuntimeCapabilities, canUseWorkerOffscreenRender, isOffscreenCanvasSupported, isOffscreenCanvas2DSupported, isTransferControlToOffscreenSupported, isCanvas2DSupported, detectSubtitleFormat, fetchSubtitleAsset, fetchSubtitleText, probeRangeSupport, renderFrameData, toBlob, toCanvas, toImageBitmap, createSubtitleDiagnosticError, normalizeSubtitleError, SubtitleDiagnosticError, type AssetFetchOptions, type AssetFetchProgress, type AssetFetchStrategy, type AutoSubtitleSource, type AutoVideoSubtitleOptions, type LiveSubtitleRenderer, type OpenedSubtitles, type RangeProbeResult, type RuntimeCapabilities, type SubtitleAspectMode, type SubtitleCacheStats, type SubtitleCueBounds, type SubtitleCueMetadata, type SubtitleData, type SubtitleDiagnosticDetailValue, type SubtitleDiagnosticErrorCode, type SubtitleDiagnosticErrorLike, type SubtitleDiagnosticsOptions, type SubtitleDiagnosticWarning, type SubtitleDiagnosticWarningCode, type SubtitleCompositionData, type SubtitleDisplaySettings, type SubtitleFrameCanvasOptions, type SubtitleFrameCanvasTarget, type SubtitleFrameCropMode, type SubtitleFrameRenderOptions, type SubtitleRenderedFrameData, type SubtitleFormatName, type SubtitleHorizontalAlign, type SubtitleLastRenderInfo, type SubtitleParserMetadata, type SubtitlePresentPath, type SubtitleRendererBackend, type SubtitleRendererEvent, type SubtitleRendererStatsSnapshot, type SubtitleStreamChunk, type SubtitleSynchronizationMode } from './wrapper';
|
|
9
9
|
export type { RenderResult, SubtitleFrame, VobSubFrame } from './wrapper';
|
|
10
10
|
export { PGSRenderer, VobsubRenderer, UnifiedSubtitleRenderer } from './wrapper';
|
|
11
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,WAAW,EACX,cAAc,EACd,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC3B,MAAM,WAAW,CAAA;AAGlB,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,EAC3B,MAAM,WAAW,CAAA;AAGlB,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAG5G,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,MAAM,EACN,KAAK,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,0BAA0B,EAC1B,4BAA4B,EAC5B,qCAAqC,EACrC,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,MAAM,EACN,QAAQ,EACR,aAAa,EACb,6BAA6B,EAC7B,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,EAC1B,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,mBAAmB,EACxB,KAAK,2BAA2B,EACjC,MAAM,WAAW,CAAA;AAGlB,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAGzE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
6
|
// High-level video-integrated renderers (compatible with old libpgs-js API)
|
|
7
|
-
export { PgsRenderer, VobSubRenderer, createAutoSubtitleRenderer } from './wrapper';
|
|
7
|
+
export { PgsRenderer, DvbRenderer, VobSubRenderer, createAutoSubtitleRenderer } from './wrapper';
|
|
8
8
|
// Low-level parsers for programmatic use
|
|
9
|
-
export { PgsParser, VobSubParserLowLevel, UnifiedSubtitleParser, openSubtitles } from './wrapper';
|
|
9
|
+
export { PgsParser, DvbParser, VobSubParserLowLevel, UnifiedSubtitleParser, openSubtitles } from './wrapper';
|
|
10
10
|
// Utility exports
|
|
11
|
-
export { initWasm, isWasmInitialized, isWebGPUSupported, detectSubtitleFormat, renderFrameData, toBlob, toCanvas, toImageBitmap, createSubtitleDiagnosticError, normalizeSubtitleError, SubtitleDiagnosticError } from './wrapper';
|
|
11
|
+
export { initWasm, isWasmInitialized, isWebGPUSupported, isWorkerAvailable, isWorkerReady, warmup, ready, getRuntimeCapabilities, canUseWorkerOffscreenRender, isOffscreenCanvasSupported, isOffscreenCanvas2DSupported, isTransferControlToOffscreenSupported, isCanvas2DSupported, detectSubtitleFormat, fetchSubtitleAsset, fetchSubtitleText, probeRangeSupport, renderFrameData, toBlob, toCanvas, toImageBitmap, createSubtitleDiagnosticError, normalizeSubtitleError, SubtitleDiagnosticError } from './wrapper';
|
|
12
12
|
// Legacy aliases
|
|
13
13
|
export { PGSRenderer, VobsubRenderer, UnifiedSubtitleRenderer } from './wrapper';
|
|
14
14
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4EAA4E;AAC5E,OAAO,EACL,WAAW,EACX,cAAc,EACd,0BAA0B,EAI3B,MAAM,WAAW,CAAA;AAElB,yCAAyC;AACzC,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,4EAA4E;AAC5E,OAAO,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,0BAA0B,EAI3B,MAAM,WAAW,CAAA;AAElB,yCAAyC;AACzC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE5G,kBAAkB;AAClB,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,MAAM,EACN,KAAK,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,0BAA0B,EAC1B,4BAA4B,EAC5B,qCAAqC,EACrC,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,MAAM,EACN,QAAQ,EACR,aAAa,EACb,6BAA6B,EAC7B,sBAAsB,EACtB,uBAAuB,EAsCxB,MAAM,WAAW,CAAA;AAKlB,iBAAiB;AACjB,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional hls.js adapter for libbitsub bitmap subtitles.
|
|
3
|
+
*
|
|
4
|
+
* hls.js handles HLS media and WebVTT/IMSC text tracks; use this helper for
|
|
5
|
+
* external PGS/VobSub/MKS bitmap overlays on the same media element.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import Hls from 'hls.js'
|
|
10
|
+
* import { attachBitSubToHls } from 'libbitsub/hlsjs'
|
|
11
|
+
*
|
|
12
|
+
* const hls = new Hls()
|
|
13
|
+
* hls.loadSource(playlistUrl)
|
|
14
|
+
* hls.attachMedia(video)
|
|
15
|
+
* const bitsub = attachBitSubToHls(hls, { subUrl: '/subs/movie.sup' })
|
|
16
|
+
* // later
|
|
17
|
+
* bitsub.dispose()
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import { type AttachBitSubOptions, type BitSubController } from './shared';
|
|
21
|
+
/** Minimal hls.js surface used by the adapter. */
|
|
22
|
+
export interface HlsLike {
|
|
23
|
+
media: HTMLMediaElement | null;
|
|
24
|
+
on?(event: string, listener: (...args: unknown[]) => void): void;
|
|
25
|
+
off?(event: string, listener: (...args: unknown[]) => void): void;
|
|
26
|
+
/** hls.js Events map — optional so callers can pass event name strings. */
|
|
27
|
+
Events?: {
|
|
28
|
+
MEDIA_ATTACHED?: string;
|
|
29
|
+
MEDIA_DETACHED?: string;
|
|
30
|
+
DESTROYING?: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export type BitSubHlsOptions = AttachBitSubOptions;
|
|
34
|
+
export interface BitSubHlsHandle extends BitSubController {
|
|
35
|
+
/** Underlying hls.js instance. */
|
|
36
|
+
readonly hls: HlsLike;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Attach libbitsub to an hls.js instance.
|
|
40
|
+
* Binds to `hls.media` and re-attaches on MEDIA_ATTACHED when event APIs exist.
|
|
41
|
+
*/
|
|
42
|
+
export declare function attachBitSubToHls(hls: HlsLike, options?: BitSubHlsOptions): BitSubHlsHandle;
|
|
43
|
+
export type { AttachBitSubOptions, BitSubController, BitSubSourceOptions, BitSubRenderer } from './shared';
|
|
44
|
+
export { attachBitSub, createBitSubRenderer } from './shared';
|
|
45
|
+
//# sourceMappingURL=hlsjs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hlsjs.d.ts","sourceRoot":"","sources":["../../src/integrations/hlsjs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAgB,KAAK,mBAAmB,EAAE,KAAK,gBAAgB,EAA4B,MAAM,UAAU,CAAA;AAElH,kDAAkD;AAClD,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAC9B,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IAChE,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IACjE,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QACP,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,CAAA;AAElD,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,kCAAkC;IAClC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;CACtB;AAUD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAgG/F;AAED,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC1G,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA"}
|