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/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
- let lastCurrentTimeReceivedAt = Date.now()
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 | ArrayBuffer
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 = (Date.now() - lastCurrentTimeReceivedAt) / 1000
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 = Date.now()
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 = Date.now()
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.HEAPU8C.slice(pointer, pointer + byteLength)
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 buf = self.wasmMemory.buffer.slice(imagePtr, imagePtr + item.w * item.h * 4)
1043
- buffers.push(buf)
1044
- item.image = buf
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 = Date.now()
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
- new Uint8ClampedArray(
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 = Date.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.height, self.width)
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.height, self.width)
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
  // =============================================================================