akarisub 0.1.0 → 0.2.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 +14 -0
- package/dist/akarisub-worker.js +2 -2
- package/dist/akarisub-worker.wasm +0 -0
- package/dist/akarisub.umd.js +5 -5
- package/dist/index.js +5 -5
- package/package.json +1 -1
- package/src/ts/akarisub.ts +148 -71
- package/src/ts/types.ts +4 -13
- package/src/ts/webgl2-renderer.ts +7 -2
- package/src/ts/webgpu-renderer.ts +12 -4
- package/src/ts/worker.ts +31 -78
package/src/ts/worker.ts
CHANGED
|
@@ -49,7 +49,8 @@ let lastCurrentTime = 0
|
|
|
49
49
|
let rate = 1
|
|
50
50
|
let rafId: number | null = null
|
|
51
51
|
let nextIsRaf = false
|
|
52
|
-
|
|
52
|
+
const nowMs = (): number => (typeof performance !== 'undefined' ? performance.now() : Date.now())
|
|
53
|
+
let lastCurrentTimeReceivedAt = nowMs()
|
|
53
54
|
let targetFps = 24
|
|
54
55
|
let onDemandRenderMode = false
|
|
55
56
|
let useLocalFonts = false
|
|
@@ -105,6 +106,7 @@ let bufferCtx: OffscreenCanvasRenderingContext2D | null = null
|
|
|
105
106
|
let akariSubHandle = 0
|
|
106
107
|
let subtitleColorSpace: SubtitleColorSpace = null
|
|
107
108
|
let dropAllBlur = false
|
|
109
|
+
let fullTrackWarmupEnabled = false
|
|
108
110
|
let hasBitmapBug = false
|
|
109
111
|
let _Module: AkariSubModule | null = null
|
|
110
112
|
let forceNextDemandRender = false
|
|
@@ -132,11 +134,6 @@ interface AkariSubApi {
|
|
|
132
134
|
removeStyle: (handle: number, index: number) => void
|
|
133
135
|
styleOverrideIndex: (handle: number, index: number) => void
|
|
134
136
|
disableStyleOverride: (handle: number) => void
|
|
135
|
-
renderBlend: (handle: number, time: number, force: number) => number
|
|
136
|
-
renderImage: (handle: number, time: number, force: number) => number
|
|
137
|
-
getChanged: (handle: number) => number
|
|
138
|
-
getCount: (handle: number) => number
|
|
139
|
-
getTime: (handle: number) => number
|
|
140
137
|
getTrackColorSpace: (handle: number) => number
|
|
141
138
|
eventGetInt: (handle: number, index: number, field: number) => number
|
|
142
139
|
eventSetInt: (handle: number, index: number, field: number, value: number) => void
|
|
@@ -146,13 +143,6 @@ interface AkariSubApi {
|
|
|
146
143
|
styleSetNum: (handle: number, index: number, field: number, value: number) => void
|
|
147
144
|
styleGetStr: (handle: number, index: number, field: number) => number
|
|
148
145
|
styleSetStr: (handle: number, index: number, field: number, valuePtr: number) => void
|
|
149
|
-
rrX: (ptr: number) => number
|
|
150
|
-
rrY: (ptr: number) => number
|
|
151
|
-
rrW: (ptr: number) => number
|
|
152
|
-
rrH: (ptr: number) => number
|
|
153
|
-
rrImage: (ptr: number) => number
|
|
154
|
-
rrNext: (ptr: number) => number
|
|
155
|
-
rrCollect: (resultPtr: number, outPtr: number, maxItems: number) => number
|
|
156
146
|
renderBlendCollect: (handle: number, time: number, force: number, outPtr: number, maxItems: number) => number
|
|
157
147
|
renderImageCollect: (handle: number, time: number, force: number, outPtr: number, maxItems: number) => number
|
|
158
148
|
}
|
|
@@ -173,12 +163,9 @@ const FULL_WARMUP_YIELD_EVERY = 24
|
|
|
173
163
|
const ASS_TIME_SCALE = 1000
|
|
174
164
|
const imagePool: RenderResultItem[] = new Array(MAX_POOLED_IMAGES)
|
|
175
165
|
let poolInitialized = false
|
|
176
|
-
const RR_META_STRIDE = 6
|
|
177
166
|
// Batch render-collect buffer: 3 header ints (changed, count, time) + 5 ints per image (x, y, w, h, image_ptr)
|
|
178
167
|
const RRC_HEADER_INTS = 3
|
|
179
168
|
const RRC_IMG_STRIDE = 5
|
|
180
|
-
let rrMetaPtr = 0
|
|
181
|
-
let rrMetaCapacity = 0
|
|
182
169
|
// Pre-allocated buffer for batch render-collect calls
|
|
183
170
|
let rrcBufPtr = 0
|
|
184
171
|
let rrcBufCapacity = 0
|
|
@@ -199,7 +186,7 @@ interface RenderResultItem {
|
|
|
199
186
|
h: number
|
|
200
187
|
x: number
|
|
201
188
|
y: number
|
|
202
|
-
image: number | ImageBitmap |
|
|
189
|
+
image: number | ImageBitmap | Uint8ClampedArray
|
|
203
190
|
}
|
|
204
191
|
|
|
205
192
|
const initPool = (): void => {
|
|
@@ -217,28 +204,6 @@ const getPooledItem = (index: number): RenderResultItem => {
|
|
|
217
204
|
return { w: 0, h: 0, x: 0, y: 0, image: 0 }
|
|
218
205
|
}
|
|
219
206
|
|
|
220
|
-
const ensureRenderMetaBuffer = (imageCount: number): void => {
|
|
221
|
-
if (!_Module || imageCount <= 0) return
|
|
222
|
-
if (rrMetaCapacity >= imageCount && rrMetaPtr) return
|
|
223
|
-
|
|
224
|
-
const nextCapacity = Math.max(imageCount, rrMetaCapacity * 2 || 64)
|
|
225
|
-
const nextSizeBytes = nextCapacity * RR_META_STRIDE * Int32Array.BYTES_PER_ELEMENT
|
|
226
|
-
|
|
227
|
-
if (rrMetaPtr) {
|
|
228
|
-
_Module._free(rrMetaPtr)
|
|
229
|
-
rrMetaPtr = 0
|
|
230
|
-
rrMetaCapacity = 0
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
rrMetaPtr = _Module._malloc(nextSizeBytes)
|
|
234
|
-
if (!rrMetaPtr) {
|
|
235
|
-
rrMetaCapacity = 0
|
|
236
|
-
throw new Error('Failed to allocate render metadata buffer')
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
rrMetaCapacity = nextCapacity
|
|
240
|
-
}
|
|
241
|
-
|
|
242
207
|
/**
|
|
243
208
|
* Ensure the batch render-collect buffer is large enough.
|
|
244
209
|
* Layout: [changed, count, time, (x, y, w, h, image_ptr) * N]
|
|
@@ -281,6 +246,10 @@ const prewarmRenderer = (time: number): void => {
|
|
|
281
246
|
}
|
|
282
247
|
}
|
|
283
248
|
|
|
249
|
+
const syncTotalEventsMetric = (): void => {
|
|
250
|
+
metrics.totalEvents = akariSubHandle ? requireApi().getEventCount(akariSubHandle) : 0
|
|
251
|
+
}
|
|
252
|
+
|
|
284
253
|
const getFirstEventStartTime = (): number | null => {
|
|
285
254
|
if (!akariSubHandle) return null
|
|
286
255
|
|
|
@@ -377,7 +346,7 @@ const stopWarmup = (): void => {
|
|
|
377
346
|
}
|
|
378
347
|
|
|
379
348
|
const scheduleFullTrackWarmup = (): void => {
|
|
380
|
-
if (fullTrackWarmupPromise || !akariSubHandle) return
|
|
349
|
+
if (!fullTrackWarmupEnabled || fullTrackWarmupPromise || !akariSubHandle) return
|
|
381
350
|
|
|
382
351
|
fullTrackWarmupPromise = (async () => {
|
|
383
352
|
await sleep(0)
|
|
@@ -778,6 +747,7 @@ self.setTrack = ({ content }: { content: string }): void => {
|
|
|
778
747
|
withCString(content, (contentPtr) => {
|
|
779
748
|
api.createTrackMem(handle, contentPtr)
|
|
780
749
|
})
|
|
750
|
+
syncTotalEventsMetric()
|
|
781
751
|
firstTrackEventStartTime = getFirstEventStartTime()
|
|
782
752
|
subtitleColorSpace = libassYCbCrMap[api.getTrackColorSpace(handle)]
|
|
783
753
|
forceNextDemandRender = true
|
|
@@ -795,6 +765,7 @@ self.freeTrack = (): void => {
|
|
|
795
765
|
const api = requireApi()
|
|
796
766
|
const handle = requireHandle()
|
|
797
767
|
api.removeTrack(handle)
|
|
768
|
+
syncTotalEventsMetric()
|
|
798
769
|
}
|
|
799
770
|
|
|
800
771
|
self.setTrackByUrl = ({ url }: { url: string }): void => {
|
|
@@ -808,7 +779,7 @@ self.setTrackByUrl = ({ url }: { url: string }): void => {
|
|
|
808
779
|
let _isPaused = true
|
|
809
780
|
|
|
810
781
|
const getCurrentTime = (): number => {
|
|
811
|
-
const diff = (
|
|
782
|
+
const diff = (nowMs() - lastCurrentTimeReceivedAt) / 1000
|
|
812
783
|
if (_isPaused) {
|
|
813
784
|
return lastCurrentTime
|
|
814
785
|
} else {
|
|
@@ -822,7 +793,7 @@ const getCurrentTime = (): number => {
|
|
|
822
793
|
|
|
823
794
|
const setCurrentTime = (currentTime: number): void => {
|
|
824
795
|
lastCurrentTime = currentTime
|
|
825
|
-
lastCurrentTimeReceivedAt =
|
|
796
|
+
lastCurrentTimeReceivedAt = nowMs()
|
|
826
797
|
|
|
827
798
|
if (onDemandRenderMode) {
|
|
828
799
|
return
|
|
@@ -859,7 +830,7 @@ const setIsPaused = (isPaused: boolean): void => {
|
|
|
859
830
|
rafId = null
|
|
860
831
|
}
|
|
861
832
|
} else {
|
|
862
|
-
lastCurrentTimeReceivedAt =
|
|
833
|
+
lastCurrentTimeReceivedAt = nowMs()
|
|
863
834
|
rafId = requestAnimationFrame(renderLoop)
|
|
864
835
|
}
|
|
865
836
|
}
|
|
@@ -960,8 +931,6 @@ const render = (time: number, force?: boolean | number): void => {
|
|
|
960
931
|
metrics.cacheHits++
|
|
961
932
|
}
|
|
962
933
|
|
|
963
|
-
metrics.totalEvents = api.getEventCount(handle)
|
|
964
|
-
|
|
965
934
|
if (debug) {
|
|
966
935
|
const decodeEndTime = performance.now()
|
|
967
936
|
const renderEndTimeWasm = headerView[2]
|
|
@@ -998,7 +967,7 @@ const render = (time: number, force?: boolean | number): void => {
|
|
|
998
967
|
|
|
999
968
|
const pointer = meta[metaOffset + 4]
|
|
1000
969
|
const byteLength = item.w * item.h * 4
|
|
1001
|
-
const rawData = self.
|
|
970
|
+
const rawData = new Uint8ClampedArray(self.wasmMemory.buffer, pointer, byteLength)
|
|
1002
971
|
|
|
1003
972
|
const imageData = new ImageData(rawData as Uint8ClampedArray<ArrayBuffer>, item.w, item.h)
|
|
1004
973
|
|
|
@@ -1039,9 +1008,11 @@ const render = (time: number, force?: boolean | number): void => {
|
|
|
1039
1008
|
|
|
1040
1009
|
if (!offCanvasCtx) {
|
|
1041
1010
|
const imagePtr = item.image as number
|
|
1042
|
-
const
|
|
1043
|
-
|
|
1044
|
-
|
|
1011
|
+
const byteLength = item.w * item.h * 4
|
|
1012
|
+
const copiedData = new Uint8ClampedArray(byteLength)
|
|
1013
|
+
copiedData.set(self.HEAPU8C.subarray(imagePtr, imagePtr + byteLength))
|
|
1014
|
+
buffers.push(copiedData.buffer)
|
|
1015
|
+
item.image = copiedData
|
|
1045
1016
|
}
|
|
1046
1017
|
images[i] = item
|
|
1047
1018
|
}
|
|
@@ -1056,7 +1027,7 @@ const render = (time: number, force?: boolean | number): void => {
|
|
|
1056
1027
|
|
|
1057
1028
|
self.demand = ({ time }: { time: number }): void => {
|
|
1058
1029
|
lastCurrentTime = time
|
|
1059
|
-
lastCurrentTimeReceivedAt =
|
|
1030
|
+
lastCurrentTimeReceivedAt = nowMs()
|
|
1060
1031
|
const force = forceNextDemandRender ? 1 : 0
|
|
1061
1032
|
forceNextDemandRender = false
|
|
1062
1033
|
render(time, force)
|
|
@@ -1132,11 +1103,7 @@ const paintImages = ({
|
|
|
1132
1103
|
|
|
1133
1104
|
bufferCtx!.putImageData(
|
|
1134
1105
|
new ImageData(
|
|
1135
|
-
|
|
1136
|
-
rawData.buffer,
|
|
1137
|
-
rawData.byteOffset,
|
|
1138
|
-
rawData.byteLength
|
|
1139
|
-
) as Uint8ClampedArray<ArrayBuffer>,
|
|
1106
|
+
rawData as Uint8ClampedArray<ArrayBuffer>,
|
|
1140
1107
|
imgW,
|
|
1141
1108
|
imgH
|
|
1142
1109
|
),
|
|
@@ -1188,7 +1155,7 @@ const paintImages = ({
|
|
|
1188
1155
|
const requestAnimationFrame = self.requestAnimationFrame ? self.requestAnimationFrame.bind(self) : ((): ((func: () => void) => number) => {
|
|
1189
1156
|
let nextRAF = 0
|
|
1190
1157
|
return (func: () => void): number => {
|
|
1191
|
-
const now =
|
|
1158
|
+
const now = nowMs()
|
|
1192
1159
|
if (nextRAF === 0) {
|
|
1193
1160
|
nextRAF = now + 1000 / targetFps
|
|
1194
1161
|
} else {
|
|
@@ -1209,6 +1176,7 @@ const cancelAnimationFrame = self.cancelAnimationFrame ? self.cancelAnimationFra
|
|
|
1209
1176
|
|
|
1210
1177
|
self.init = async (data: any): Promise<void> => {
|
|
1211
1178
|
hasBitmapBug = data.hasBitmapBug
|
|
1179
|
+
fullTrackWarmupEnabled = !!data.fullTrackWarmup
|
|
1212
1180
|
if (typeof data.initialTime === 'number' && Number.isFinite(data.initialTime)) {
|
|
1213
1181
|
lastCurrentTime = data.initialTime
|
|
1214
1182
|
}
|
|
@@ -1254,11 +1222,6 @@ self.init = async (data: any): Promise<void> => {
|
|
|
1254
1222
|
removeStyle: Module._akarisub_remove_style,
|
|
1255
1223
|
styleOverrideIndex: Module._akarisub_style_override_index,
|
|
1256
1224
|
disableStyleOverride: Module._akarisub_disable_style_override,
|
|
1257
|
-
renderBlend: Module._akarisub_render_blend,
|
|
1258
|
-
renderImage: Module._akarisub_render_image,
|
|
1259
|
-
getChanged: Module._akarisub_get_changed,
|
|
1260
|
-
getCount: Module._akarisub_get_count,
|
|
1261
|
-
getTime: Module._akarisub_get_time,
|
|
1262
1225
|
getTrackColorSpace: Module._akarisub_get_track_color_space,
|
|
1263
1226
|
eventGetInt: Module._akarisub_event_get_int,
|
|
1264
1227
|
eventSetInt: Module._akarisub_event_set_int,
|
|
@@ -1268,13 +1231,6 @@ self.init = async (data: any): Promise<void> => {
|
|
|
1268
1231
|
styleSetNum: Module._akarisub_style_set_num,
|
|
1269
1232
|
styleGetStr: Module._akarisub_style_get_str,
|
|
1270
1233
|
styleSetStr: Module._akarisub_style_set_str,
|
|
1271
|
-
rrX: Module._akarisub_render_result_x,
|
|
1272
|
-
rrY: Module._akarisub_render_result_y,
|
|
1273
|
-
rrW: Module._akarisub_render_result_w,
|
|
1274
|
-
rrH: Module._akarisub_render_result_h,
|
|
1275
|
-
rrImage: Module._akarisub_render_result_image,
|
|
1276
|
-
rrNext: Module._akarisub_render_result_next,
|
|
1277
|
-
rrCollect: Module._akarisub_render_result_collect,
|
|
1278
1234
|
renderBlendCollect: Module._akarisub_render_blend_collect,
|
|
1279
1235
|
renderImageCollect: Module._akarisub_render_image_collect
|
|
1280
1236
|
}
|
|
@@ -1535,11 +1491,10 @@ self.init = async (data: any): Promise<void> => {
|
|
|
1535
1491
|
if (debug) console.log('[AkariSub] Font reload complete')
|
|
1536
1492
|
}
|
|
1537
1493
|
|
|
1538
|
-
processAvailableFonts(subContent)
|
|
1539
|
-
|
|
1540
1494
|
withCString(subContent, (subPtr) => {
|
|
1541
1495
|
requireApi().createTrackMem(requireHandle(), subPtr)
|
|
1542
1496
|
})
|
|
1497
|
+
syncTotalEventsMetric()
|
|
1543
1498
|
firstTrackEventStartTime = getFirstEventStartTime()
|
|
1544
1499
|
subtitleColorSpace = libassYCbCrMap[requireApi().getTrackColorSpace(requireHandle())]
|
|
1545
1500
|
requireApi().setDropAnimations(requireHandle(), data.dropAllAnimations || 0)
|
|
@@ -1576,16 +1531,16 @@ self.init = async (data: any): Promise<void> => {
|
|
|
1576
1531
|
|
|
1577
1532
|
self.offscreenCanvas = ({ transferable }: { transferable: [OffscreenCanvas] }): void => {
|
|
1578
1533
|
offCanvas = transferable[0]
|
|
1579
|
-
offCanvasCtx = offCanvas.getContext('2d')
|
|
1534
|
+
offCanvasCtx = offCanvas.getContext('2d', { desynchronized: true })
|
|
1580
1535
|
if (!asyncRender) {
|
|
1581
|
-
bufferCanvas = new OffscreenCanvas(self.
|
|
1536
|
+
bufferCanvas = new OffscreenCanvas(self.width, self.height)
|
|
1582
1537
|
bufferCtx = bufferCanvas.getContext('2d', { desynchronized: true })
|
|
1583
1538
|
}
|
|
1584
1539
|
offscreenRender = true
|
|
1585
1540
|
}
|
|
1586
1541
|
|
|
1587
1542
|
self.detachOffscreen = (): void => {
|
|
1588
|
-
offCanvas = new OffscreenCanvas(self.
|
|
1543
|
+
offCanvas = new OffscreenCanvas(self.width, self.height)
|
|
1589
1544
|
offCanvasCtx = offCanvas.getContext('2d', { desynchronized: true })
|
|
1590
1545
|
offscreenRender = 'hybrid'
|
|
1591
1546
|
}
|
|
@@ -1630,11 +1585,6 @@ self.destroy = (): void => {
|
|
|
1630
1585
|
firstTrackEventStartTime = null
|
|
1631
1586
|
|
|
1632
1587
|
if (_Module) {
|
|
1633
|
-
if (rrMetaPtr) {
|
|
1634
|
-
_Module._free(rrMetaPtr)
|
|
1635
|
-
rrMetaPtr = 0
|
|
1636
|
-
rrMetaCapacity = 0
|
|
1637
|
-
}
|
|
1638
1588
|
if (rrcBufPtr) {
|
|
1639
1589
|
_Module._free(rrcBufPtr)
|
|
1640
1590
|
rrcBufPtr = 0
|
|
@@ -1645,6 +1595,7 @@ self.destroy = (): void => {
|
|
|
1645
1595
|
requireApi().destroy(akariSubHandle)
|
|
1646
1596
|
akariSubHandle = 0
|
|
1647
1597
|
}
|
|
1598
|
+
metrics.totalEvents = 0
|
|
1648
1599
|
}
|
|
1649
1600
|
|
|
1650
1601
|
self.setAsyncRender = ({ value }: { value: boolean }): void => {
|
|
@@ -1749,6 +1700,7 @@ const readStyle = (index: number): ASSStyle => {
|
|
|
1749
1700
|
self.createEvent = ({ event }: { event: Partial<ASSEvent> }): void => {
|
|
1750
1701
|
const index = requireApi().allocEvent(requireHandle())
|
|
1751
1702
|
if (index >= 0) applyEventFields(index, event)
|
|
1703
|
+
syncTotalEventsMetric()
|
|
1752
1704
|
}
|
|
1753
1705
|
|
|
1754
1706
|
self.getEvents = (): void => {
|
|
@@ -1767,6 +1719,7 @@ self.setEvent = ({ event, index }: { event: Partial<ASSEvent>; index: number }):
|
|
|
1767
1719
|
|
|
1768
1720
|
self.removeEvent = ({ index }: { index: number }): void => {
|
|
1769
1721
|
requireApi().removeEvent(requireHandle(), index)
|
|
1722
|
+
syncTotalEventsMetric()
|
|
1770
1723
|
}
|
|
1771
1724
|
|
|
1772
1725
|
// =============================================================================
|