fix(jassub): [PKG-JASSUB-10] release bitmap batches on rendering errors

This commit is contained in:
Harvey Zhao committed 2026-09-14 15:28:52 +08:00
1 parent 04060aa8b6
commit 7b0e1d156b
22 files changed
+5795 -22

No files matched your search

@@ -0,0 +1,11 @@
{
"task": "PKG-JASSUB-10",
"baselineCommit": "04060aa8b6b5cf070bac0c6a9d50eb329fab9719",
"file": "packages/artplayer-plugin-jassub/src/jassub.es.js",
"originalSha256LF": "60590f2fca6ffded74f96f8a6001a86c32eb38f5e1fae26338cbbb43e93fb70a",
"patchedSha256LF": "ebabca473edfbe7f9768dba25b2c2403f2c9c5dec64292fa008d8eb758e32696",
"patchFile": "refactor/baselines/jassub-render.patch",
"patchSha256LF": "4de7af48eef2839e3b569592586132cca7c2a1ff0222a1fe14a06835ed11cb74",
"predecessor": "refactor/baselines/jassub-hybrid-patch.json",
"purpose": "Release the complete async bitmap batch on native canvas rendering failure while preserving the exception and synchronous ImageData path."
}
File diff suppressed because it is too large. Load diff
+21
View File
@@ -0,0 +1,21 @@
diff --git a/packages/artplayer-plugin-jassub/src/jassub.es.js b/packages/artplayer-plugin-jassub/src/jassub.es.js
index 88088b0ca..ea3c2d06f 100644
--- a/packages/artplayer-plugin-jassub/src/jassub.es.js
+++ b/packages/artplayer-plugin-jassub/src/jassub.es.js
@@ -563,9 +563,13 @@ class o extends EventTarget {
for (const image of e) image.image?.close?.();
return;
}
- this._unbusy(), this.debug && (s.IPCTime = Date.now() - s.JSRenderTime), (this._canvasctrl.width !== r || this._canvasctrl.height !== n) && (this._canvasctrl.width = r, this._canvasctrl.height = n, this._verifyColorSpace({ subtitleColorSpace: a })), this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
- for (const i of e)
- i.image && (t ? (this._ctx.drawImage(i.image, i.x, i.y), i.image.close()) : (this._bufferCanvas.width = i.w, this._bufferCanvas.height = i.h, this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)), i.w, i.h), 0, 0), this._ctx.drawImage(this._bufferCanvas, i.x, i.y)));
+ try {
+ this._unbusy(), this.debug && (s.IPCTime = Date.now() - s.JSRenderTime), (this._canvasctrl.width !== r || this._canvasctrl.height !== n) && (this._canvasctrl.width = r, this._canvasctrl.height = n, this._verifyColorSpace({ subtitleColorSpace: a })), this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
+ for (const i of e)
+ i.image && (t ? this._ctx.drawImage(i.image, i.x, i.y) : (this._bufferCanvas.width = i.w, this._bufferCanvas.height = i.h, this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)), i.w, i.h), 0, 0), this._ctx.drawImage(this._bufferCanvas, i.x, i.y)));
+ } finally {
+ if (t) for (const i of e) i.image?.close();
+ }
if (this.debug) {
s.JSRenderTime = Date.now() - s.JSRenderTime - s.IPCTime;
let i = 0;
@@ -0,0 +1,47 @@
# PKG-JASSUB-10 绘制异常后的位图释放
修复主线程 asyncRender 的整批资源归属。旧 wrapper 在 drawImage 成功之后才关闭
当前 ImageBitmap;clearRect、画布尺寸更新或任意一次 drawImage 抛错,会跳过当前
和剩余位图的释放。现在在 finally 释放本消息的整个异步位图批次,原生异常继续
向调用方传播;正常绘制顺序、Worker 协议、公开类型和默认渲染模式保持不变。
同步 ImageData/ArrayBuffer 路径不执行 bitmap.close。
受控测试注入四种失败位置并验证异常对象、绘制次数及每张位图只释放一次。另有
同步缓冲区对照;既有正常 hybrid 绘制、迟到帧及销毁回归保留。原始源码16项中
12通过4失败;这四项都是资源释放断言失败。
原生浏览器测试从真实 JASSUB Worker/WASM 接收 ImageBitmap,再创建两个原生
副本作为同批后续位图。主动关闭第一张触发原生 InvalidStateError,检查其余位图
width归零并强制下一帧绘制,绿色字幕像素必须恢复。它证明受控异常后的清理,
不声称 Worker 会自然产出损坏位图,也不把它当成 Firefox 默认 offscreen 停顿的
根因或修复。初版测试误读 plugins.add 返回值导致的三项初始化失败单独保留;
修正后旧产物三浏览器都在剩余位图未释放的断言失败,不能混用两轮失败证据。
首轮候选的位图释放三浏览器都通过,但两项字幕恢复失败。原因是测试在仍有待处理
demand 时调用 resize(force),现有实现有意忽略 busy 状态的强制重绘。测试现在暂停
原生video、等待当前需求完成,再调用同一公开resize;没有修改生产时钟,也没有
延长等待。最终main三项异常恢复通过;legacy与正常播放合跑12项通过。旧产物以
最终浏览器测试重新执行,三项仍在位图释放断言失败,证明不是等待变化掩盖缺陷。
最终验证:
- 固定 Node24.21.0 / Yarn1.22.22;严格工具链检查通过。
- 全包201项通过;实际main/legacy的运行时、生命周期、帧回调、offscreen组各69项通过。
- 最终受控旧main16项中12通过4失败;源码修复后的对应测试通过。仅在最后添加测试
if分支的格式花括号,不改变条件或断言;lint最终通过。
- 正常main/legacy/ESM均正常构建,分别与docs副本核对字节;严格包TS通过,核心37份
生成声明无漂移。没有修改消费者声明,未把已有安装验收报告当成此次重新安装。
- main:3项真实位图异常/恢复,以及三核心×三浏览器9项真实WASM字幕播放、seek、
布局、资源销毁;legacy同样12项通过。无重试、无跳过。
- 浏览器为Windows Chromium153.0.8010.12、Firefox155.0、WebKit26.6;明确主线程
asyncRender。原生故障注入仅candidate核心,正常播放另含两个旧核心。不是物理
Apple/Android设备、默认offscreen、持续GPU内存压力、完整组合或远端CI验收。
本次是独立任务,依赖已完成的初始化/生命周期基础。当前Git基线包含09尚未全部
验收的修复检查点;其未关闭的默认模式问题继续由09/05跟踪,不能因10通过而关闭。
第四段vendor补丁保留前三段原指纹与可逆diff,第三方清单记录最新实际源码指纹。
没有更换Worker/WASM/字体、依赖、版本、公开声明或发行入口。
验证结果和具体候选/报告指纹见
[机器记录](../baselines/jassub-render-validation.json)。回退本任务独立提交并正常
重建包可恢复旧行为;不要只改来源清单或只回退一份分发格式。没有push/publish。
+6 -4
View File
@@ -2,9 +2,9 @@
> 由 tasks.json 生成。请修改数据后运行 `node refactor/scripts/plan.mjs --write`,不要手改本表。
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 253 项,范围 22 个包及工作区/示例。
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 254 项,范围 22 个包及工作区/示例。
状态:todo 54 / doing 17 / blocked 0 / done 182 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
状态:todo 54 / doing 17 / blocked 0 / done 183 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
@@ -27,7 +27,7 @@
| artplayer-plugin-dash-control | 1.1.0 | PKG-DASH-01, PKG-DASH-02, PKG-DASH-03, PKG-DASH-04, PKG-DASH-05, PKG-DASH-06 |
| artplayer-plugin-document-pip | 1.1.0 | PKG-DPIP-01, PKG-DPIP-02, PKG-DPIP-03, PKG-DPIP-04, PKG-DPIP-05, PKG-DPIP-06 |
| artplayer-plugin-hls-control | 1.1.0 | PKG-HLS-01, PKG-HLS-02, PKG-HLS-03, PKG-HLS-04, PKG-HLS-SDK-01, PKG-HLS-05, PKG-HLS-06 |
| artplayer-plugin-jassub | 1.1.0 | PKG-JASSUB-01, PKG-JASSUB-02, PKG-JASSUB-03, PKG-JASSUB-04, PKG-JASSUB-05, PKG-JASSUB-06, PKG-JASSUB-07, PKG-JASSUB-08, PKG-JASSUB-09 |
| artplayer-plugin-jassub | 1.1.0 | PKG-JASSUB-01, PKG-JASSUB-02, PKG-JASSUB-03, PKG-JASSUB-04, PKG-JASSUB-05, PKG-JASSUB-06, PKG-JASSUB-07, PKG-JASSUB-08, PKG-JASSUB-09, PKG-JASSUB-10 |
| artplayer-plugin-multiple-subtitles | 1.2.0 | PKG-MULTI-SUB-01, PKG-MULTI-SUB-02, PKG-MULTI-SUB-03, PKG-MULTI-SUB-04, PKG-MULTI-SUB-07, PKG-MULTI-SUB-08, PKG-MULTI-SUB-05, PKG-MULTI-SUB-06, PKG-MULTI-SUB-09, PKG-MULTI-SUB-10, PKG-MULTI-SUB-11 |
| artplayer-plugin-vast | 1.2.0 | PKG-VAST-01, PKG-VAST-02, PKG-VAST-03, PKG-VAST-04, PKG-VAST-05, PKG-VAST-06, PKG-VAST-07 |
| artplayer-plugin-vtt-thumbnail | 1.1.0 | PKG-VTT-THUMB-01, PKG-VTT-THUMB-02, PKG-VTT-THUMB-03, PKG-VTT-THUMB-04, PKG-VTT-THUMB-05, PKG-VTT-THUMB-06 |
@@ -243,11 +243,12 @@
| PKG-JASSUB-02 | artplayer-plugin-jassub<br>建立特有行为与错误测试 | PKG-JASSUB-01, ENG-03, ENG-05 | ASS 字体、时钟/seek/倍率/resize、加载失败和销毁 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
| PKG-JASSUB-03 | artplayer-plugin-jassub<br>整理内部职责与资源 | PKG-JASSUB-02, CORE-15, CORE-16 | 仅整理自有 adapter/销毁;保留第三方文件及来源 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
| PKG-JASSUB-04 | artplayer-plugin-jassub<br>迁移自有源码和公开类型 | PKG-JASSUB-03, ENG-04, ENG-06, CORE-07 | JASSUB option/instance 的兼容类型包装,vendor JS 例外记录 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done |
| PKG-JASSUB-05 | artplayer-plugin-jassub<br>验证新旧核心和组合 | PKG-JASSUB-04, CORE-22, PKG-JASSUB-07, PKG-JASSUB-08, PKG-JASSUB-09 | 真实 worker/WASM 字幕渲染与全屏、旧核心测试 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
| PKG-JASSUB-05 | artplayer-plugin-jassub<br>验证新旧核心和组合 | PKG-JASSUB-04, CORE-22, PKG-JASSUB-07, PKG-JASSUB-08, PKG-JASSUB-09, PKG-JASSUB-10 | 真实 worker/WASM 字幕渲染与全屏、旧核心测试 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
| PKG-JASSUB-06 | artplayer-plugin-jassub<br>验证分发并同步文档 | PKG-JASSUB-05, ENG-07 | jassub.js、外部资源路径、许可和离线失败记录;接续 VENDOR-04/05 完整组件/字体通知、LGPL 源码分发核对及六份未明确字体的分发处置 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录;来源身份已由01冻结,完整通知和未明确字体的发布处理必须闭环,不能以来源相同替代许可结论 | H | todo |
| PKG-JASSUB-07 | artplayer-plugin-jassub<br>修复 vendor 生命周期与字幕时钟 | PKG-JASSUB-03, PKG-JASSUB-02 | 独立记录 vendor 适配差异;幂等销毁、跨容器 setVideo、构造回滚、逐帧归属和倍率/能力边界;查询 timeout/Worker error 的缺失数据回调及每请求监听器/定时器清理(JASSUB-QUERY-01) | 保持公开真实 instance、同步方法与资源路径;保留原 vendor 来源指纹并记录每项实际补丁;候选修复正例和真实字幕/失败/时钟验证通过,未证实设备不得冒充通过 | H | done |
| PKG-JASSUB-08 | artplayer-plugin-jassub<br>修复默认 offscreen 初始化消息顺序 | PKG-JASSUB-07 | 在释放排队绘制消息前转移初始画布;独立 vendor 补丁、默认模式原生回归和维护文档 | 保留默认能力选择、Worker/资源和公开同步 API;旧红新绿消息顺序测试及真实默认 offscreen 播放/seek/全屏通过,主线程绘制保持 | H | done |
| PKG-JASSUB-09 | artplayer-plugin-jassub<br>修复 hybrid 迟到绘制与销毁后画布重建 | PKG-JASSUB-08 | 释放旧混合绘制 bitmap,不改变新模式的画布/时钟;销毁后切字幕不重新分配画布;来源补丁、原生排队消息及维护记录 | 旧红新绿验证旧帧不能重建画布/解除新绘制等待;正常 hybrid 绘制保持;真实 Worker/ImageBitmap 交错、主线程及默认模式回归通过,能力缺口明确 | H | doing |
| PKG-JASSUB-10 | artplayer-plugin-jassub<br>释放绘制异常后的整批 ImageBitmap | PKG-JASSUB-08 | 主线程异步绘制异常时释放整批位图;同步路径保持;原生异常/恢复测试和可逆vendor补丁记录 | 旧红新绿验证清屏、尺寸和首/后续绘制异常的释放及原异常传播;真实Worker位图和原生Canvas异常后恢复字幕;源码/main/legacy回归、类型、来源及构建通过 | M | done |
## 5 包迁移:artplayer-plugin-danmuku-mask
@@ -658,3 +659,4 @@
- PKG-MULTI-SUB-11: [记录](changes/2026-09-14-PKG-MULTI-SUB-11-ass-conversion.md) [记录](baselines/multiple-subtitles-ass-validation.json)
- PKG-AUTO-THUMB-11: [记录](changes/2026-09-14-PKG-AUTO-THUMB-11-handler-cleanup.md) [记录](baselines/auto-thumbnail-handler-validation.json)
- PKG-VAST-07: [记录](changes/2026-09-14-PKG-VAST-07-default-alias.md) [记录](baselines/vast-alias-validation.json)
- PKG-JASSUB-10: [记录](changes/2026-09-14-PKG-JASSUB-10-render-resources.md) [记录](baselines/jassub-render-validation.json) [记录](baselines/jassub-render-patch.json)
+15
View File
@@ -1,5 +1,20 @@
# 进度与证据
## PKG-JASSUB-10 绘制异常后的位图释放完成
主线程asyncRender在清屏、调整尺寸或绘制抛错时,现在通过finally释放整批收到的
ImageBitmap,保留原生异常及同步缓冲区路径。冻结旧main四项受控释放回归失败,
三浏览器以真实Worker/WASM位图及原生副本注入InvalidStateError也复现剩余位图
未释放。候选全包201项通过,main/legacy运行时组各69项;两种产物各12项真实
主线程字幕播放/seek/布局/销毁和异常恢复通过。修正测试的busy/force调用顺序后,
旧产物用最终测试仍三项失败;未修改生产调度或延长超时。
见[变更](changes/2026-09-14-PKG-JASSUB-10-render-resources.md)及
[证据](baselines/jassub-render-validation.json)。四段vendor补丁来源链、三种构建及
docs副本、严格TS、37份核心声明无漂移、定向lint和工具链检查通过。
254项:183 done、17 doing、54 todo。09/05及Firefox默认offscreen停顿保持未关闭;
此项不代表JASSUB整体、设备、远端CI或发布验收完成。下一步继续剩余包验收和
原生绘制问题定位;不把本次主线程资源修复当作默认绘制停顿的解决方案。
## REL-08 逐包发布准入台账完成
建立22包历史分发、独立major目标、能力/回退和候选证据登记。新增纯模型及只读
+1
View File
@@ -268,3 +268,4 @@
| MULTI-SUB-OFFSET-01 | resolved / 已复现 | Paused Firefox subtitle offset leaves out-of-time native cues active and captions visible | PKG-MULTI-SUB-05, CORE-SUBTITLE-OFFSET-01 |
| MULTI-SUB-SWITCH-01 | open / 已复现 | Intermittent WebKit core5.3.0 caption loss after selected-track source switch | PKG-MULTI-SUB-05, PKG-MULTI-SUB-09 |
| MULTI-SUB-ASS-01 | resolved / 已复现 | Published core5.1.2 ASS converter loses required VTT line breaks | PKG-MULTI-SUB-11 |
| JASSUB-RENDER-RESOURCES-01 | resolved / 已复现 | Main-thread async rendering leaves received ImageBitmaps open when native canvas operations throw | PKG-JASSUB-10 |
+26 -1
View File
@@ -2,7 +2,7 @@
"schemaVersion": 1,
"task": "BASE-07",
"sourceCommit": "e01f39ff",
"updatedAt": "2026-09-14T06:00:35.506Z",
"updatedAt": "2026-09-14T07:23:15.393Z",
"note": "Open means closure evidence is outstanding; source-observed and unverified are not reproduced runtime bugs. A source issue already mitigated in the workspace still requires candidate regression evidence. No accepted-with-scope item is implied by baseline task completion.",
"items": [
{
@@ -6102,6 +6102,31 @@
"refactor/baselines/multiple-subtitles-ass-validation.json"
],
"resolutionRationale": "Frozen main output fails before repair while same-version legacy/source remain correct. Exact-output repair preserves valid/custom output and exception ownership.315 package checks, actual main/legacy unit cases and source/main/legacy each21 native desktop cases prove this specific conversion defect fixed, without claiming full ASS layout, device or source-seek acceptance."
},
{
"id": "JASSUB-RENDER-RESOURCES-01",
"title": "Main-thread async rendering leaves received ImageBitmaps open when native canvas operations throw",
"confirmation": "reproduced",
"status": "resolved",
"owners": [
"PKG-JASSUB-10"
],
"evidence": [
"test/jassub-offscreen.test.js",
"test/browser/jassub-render-failure.spec.js",
"refactor/changes/2026-09-14-PKG-JASSUB-10-render-resources.md",
"refactor/baselines/jassub-render-validation.json"
],
"compatibleResolution": "Release all owned async bitmaps in finally, preserving the original native exception, ordinary draw order and synchronous pixel buffer behavior.",
"closureCriteria": "Controlled clear/resize/first/later draw failures and actual native Canvas failure release all bitmaps; normal rendering, subsequent subtitle recovery, source/built regressions, provenance and strict types pass.",
"workspaceState": "Final main/legacy release all owned bitmaps on native drawing failure; normal main-thread subtitle playback and explicit redraw recovery pass on three desktop engines. Firefox offscreen stall remains separate.",
"resolutionEvidence": [
"refactor/baselines/jassub-render-validation.json",
"refactor/changes/2026-09-14-PKG-JASSUB-10-render-resources.md",
"test/jassub-offscreen.test.js",
"test/browser/jassub-render-failure.spec.js"
],
"resolutionRationale": "Old exact main fails all four controlled disposal cases and all three native batch-disposal cases. Candidate full suite passes 201 cases; actual main/legacy runtime groups each pass 69 cases and each has 12 native failure/recovery/playback cases. The fix changes only async bitmap release on main-thread render and retains exceptions and synchronous buffers."
}
]
}
@@ -6,7 +6,7 @@ import test from 'node:test'
import { hash } from './releases.mjs'
test('JASSUB local vendor patch retains its exact original, changed source and reversible patch identity', () => {
const records = ['vendor', 'offscreen', 'hybrid'].map(name => JSON.parse(fs.readFileSync(`refactor/baselines/jassub-${name}-patch.json`, 'utf8')))
const records = ['vendor', 'offscreen', 'hybrid', 'render'].map(name => JSON.parse(fs.readFileSync(`refactor/baselines/jassub-${name}-patch.json`, 'utf8')))
for (const [index, record] of records.entries()) {
const next = records[index + 1]
const original = execFileSync('git', ['show', `${record.baselineCommit}:${record.file}`], { encoding: 'utf8' }).replaceAll('\r\n', '\n')
+22 -1
View File
@@ -2548,7 +2548,8 @@
"CORE-22",
"PKG-JASSUB-07",
"PKG-JASSUB-08",
"PKG-JASSUB-09"
"PKG-JASSUB-09",
"PKG-JASSUB-10"
],
"status": "todo",
"risk": "H",
@@ -5272,6 +5273,26 @@
"changes/2026-09-14-PKG-VAST-07-default-alias.md",
"baselines/vast-alias-validation.json"
]
},
{
"id": "PKG-JASSUB-10",
"phase": "5 包迁移:artplayer-plugin-jassub",
"title": "释放绘制异常后的整批 ImageBitmap",
"scope": [
"artplayer-plugin-jassub"
],
"dependsOn": [
"PKG-JASSUB-08"
],
"status": "done",
"risk": "M",
"deliverable": "主线程异步绘制异常时释放整批位图;同步路径保持;原生异常/恢复测试和可逆vendor补丁记录",
"acceptance": "旧红新绿验证清屏、尺寸和首/后续绘制异常的释放及原异常传播;真实Worker位图和原生Canvas异常后恢复字幕;源码/main/legacy回归、类型、来源及构建通过",
"evidence": [
"changes/2026-09-14-PKG-JASSUB-10-render-resources.md",
"baselines/jassub-render-validation.json",
"baselines/jassub-render-patch.json"
]
}
]
}
+3 -2
View File
@@ -388,7 +388,7 @@
{
"path": "packages/artplayer-plugin-jassub/src/jassub.es.js",
"algorithm": "sha256-lf",
"sha256": "60590f2fca6ffded74f96f8a6001a86c32eb38f5e1fae26338cbbb43e93fb70a"
"sha256": "ebabca473edfbe7f9768dba25b2c2403f2c9c5dec64292fa008d8eb758e32696"
},
{
"path": "packages/artplayer-plugin-jassub/worker/jassub-worker-modern.wasm",
@@ -414,7 +414,8 @@
"followUp": "refactor/baselines/jassub-offscreen-patch.json",
"followUps": [
"refactor/baselines/jassub-offscreen-patch.json",
"refactor/baselines/jassub-hybrid-patch.json"
"refactor/baselines/jassub-hybrid-patch.json",
"refactor/baselines/jassub-render-patch.json"
]
}
},