akari-video 0.1.23 → 0.1.24
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/package.json +1 -1
- package/src/chrome-command.mjs +96 -0
- package/src/cli.mjs +3 -0
- package/src/messages.mjs +1 -0
- package/vendor/.akari-capability-sources.json +7 -0
- package/vendor/docs/contract-2026-07-20-edit-json-v1-narration.md +12 -0
- package/vendor/docs/contract-2026-07-22-render-basics.md +21 -0
- package/vendor/docs/contract-2026-07-23-analysis-person-matte.md +26 -0
- package/vendor/docs/contract-2026-07-25-r6-audio-tracks-and-trim.md +8 -0
- package/vendor/docs/contract-2026-08-28-osr-export-v0.md +119 -0
- package/vendor/docs/contract-2026-08-28-v2-audio-roles-v0.md +115 -0
- package/vendor/packages/akari-launcher/README.md +14 -0
- package/vendor/packages/akari-launcher/package.json +1 -1
- package/vendor/packages/analysis-report/render-analysis-report.mjs +50 -6
- package/vendor/packages/analysis-report/template.html +11 -1
- package/vendor/packages/decision-log-report/README.md +50 -0
- package/vendor/packages/decision-log-report/package.json +13 -0
- package/vendor/packages/decision-log-report/render-decision-log-report.mjs +484 -0
- package/vendor/packages/decision-log-report/template.html +471 -0
- package/vendor/packages/edit-lint/README.md +44 -0
- package/vendor/packages/edit-lint/src/edit-lint.mjs +335 -24
- package/vendor/packages/edit-store/lib/audio-schedule.d.ts +62 -0
- package/vendor/packages/edit-store/lib/audio-schedule.js +284 -0
- package/vendor/packages/edit-store/lib/ducking.d.ts +25 -0
- package/vendor/packages/edit-store/lib/ducking.js +31 -0
- package/vendor/packages/edit-store/lib/edit-store.d.ts +2 -0
- package/vendor/packages/edit-store/lib/index.d.ts +2 -0
- package/vendor/packages/edit-store/lib/index.js +2 -0
- package/vendor/packages/edit-store/lib/internal-model.js +12 -3
- package/vendor/packages/edit-store/lib/migrate/index.js +17 -6
- package/vendor/packages/edit-store/lib/migrate/legacy-parse.js +4 -0
- package/vendor/packages/edit-store/lib/webview-kernel.d.ts +2 -0
- package/vendor/packages/edit-store/lib/webview-kernel.js +304 -0
- package/vendor/packages/frame-engine/README.ja.md +21 -2
- package/vendor/packages/frame-engine/README.md +21 -2
- package/vendor/packages/frame-engine/package.json +8 -1
- package/vendor/packages/osr-export/README.md +63 -0
- package/vendor/packages/osr-export/package.json +27 -0
- package/vendor/packages/preview-server/package.json +2 -1
- package/vendor/packages/schemas/analysis.schema.json +11 -1
- package/vendor/packages/schemas/edit.schema.json +4 -1
- package/vendor/packages/schemas/examples/edit-narration-trim-valid/edit.json +33 -0
- package/vendor/packages/schemas/test/edit-narration-trim.test.mjs +30 -0
- package/vendor/skills/analyze-footage/bin/person-matte/mask-format.mjs +25 -0
- package/vendor/skills/analyze-footage/bin/person-matte/mask-from-alpha.mjs +249 -0
- package/vendor/skills/analyze-footage/bin/person-matte/mask-roundtrip.mjs +206 -0
- package/vendor/skills/analyze-footage/bin/person-matte/person-cutout.mjs +3 -0
- package/vendor/skills/analyze-footage/bin/person-matte/person-matte.mjs +119 -4
- package/vendor/skills/analyze-footage/person-matte.md +20 -0
- package/vendor/skills/analyze-footage/test/person-matte-mask.test.mjs +85 -0
- package/vendor/skills/analyze-project/decision-record.md +3 -0
- package/vendor/skills/edit-plan/SKILL.md +3 -1
- package/vendor/skills/edit-plan/approvals-and-generation.md +2 -1
- package/vendor/skills/edit-plan/execution.md +1 -0
- package/vendor/skills/edit-plan/report-guide.md +8 -0
- package/vendor/skills/edit-plan/workflow.md +3 -0
package/README.md
CHANGED
|
@@ -52,6 +52,20 @@ DL・sha256 検証・適用まで実行。それ以外(npm グローバル / g
|
|
|
52
52
|
`packages/asset-resolver` の CLI への薄い委譲で、カタログ合成・entitlements 判定・
|
|
53
53
|
sha256 検証・fail-closed は resolver 側の責務のまま。`src/assets-command.mjs`)。
|
|
54
54
|
|
|
55
|
+
### Chrome の導入
|
|
56
|
+
|
|
57
|
+
動画の書き出しに使う Chrome for Testing は、次のコマンドで導入できる。
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
akari chrome install
|
|
61
|
+
akari chrome install --cache-dir /path/to/cache
|
|
62
|
+
akari chrome install --build-id 150.0.7339.16
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
保存先の既定は `~/.cache/puppeteer`。`--cache-dir` で保存先、`--build-id` で導入する
|
|
66
|
+
buildId を指定できる。実行環境から `@puppeteer/browsers` を解決できる必要があり、
|
|
67
|
+
AKARI Video アプリの配布物には必要なモジュールが同梱されている。
|
|
68
|
+
|
|
55
69
|
`akari` に渡した引数はそのまま `opencode` に転送する(例: `akari --continue` は
|
|
56
70
|
`opencode --continue` を起動する)。
|
|
57
71
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "AKARI Video launcher CLI — start an AI-edited video project from any directory: scaffold, connection check, then hand over to Claude Code (or opencode). AKARI Video を opencode や Claude Code で、どのディレクトリからでも始めるための `akari` ランチャー CLI。接続確認(doctor)→ 未セットアップならプロジェクト雛形を作成 → AI エージェントを起動する。外部 npm 依存ゼロ(Node.js 組み込みモジュールのみ)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const usage = [
|
|
5
|
+
'使い方: akari chrome install [options]',
|
|
6
|
+
'',
|
|
7
|
+
'オプション:',
|
|
8
|
+
' --cache-dir <dir> Chrome の保存先(既定: ~/.cache/puppeteer)',
|
|
9
|
+
' --build-id <id> 導入する Chrome の buildId(既定: stable の最新版)',
|
|
10
|
+
' -h, --help このヘルプを表示',
|
|
11
|
+
].join('\n');
|
|
12
|
+
|
|
13
|
+
class PublicError extends Error {
|
|
14
|
+
constructor(message, exitCode = 1) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.exitCode = exitCode;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseInstallArguments(argv, homeDirectory) {
|
|
21
|
+
const parsed = {
|
|
22
|
+
cacheDir: join(homeDirectory, '.cache', 'puppeteer'),
|
|
23
|
+
buildId: undefined,
|
|
24
|
+
};
|
|
25
|
+
for (let index = 1; index < argv.length; index += 1) {
|
|
26
|
+
const argument = argv[index];
|
|
27
|
+
if (argument !== '--cache-dir' && argument !== '--build-id') {
|
|
28
|
+
throw new PublicError(`不明な引数です: ${argument}`, 2);
|
|
29
|
+
}
|
|
30
|
+
const value = argv[index + 1];
|
|
31
|
+
if (value === undefined || value.startsWith('--')) {
|
|
32
|
+
throw new PublicError(`${argument} の値がありません`, 2);
|
|
33
|
+
}
|
|
34
|
+
index += 1;
|
|
35
|
+
if (argument === '--cache-dir') parsed.cacheDir = resolve(value);
|
|
36
|
+
else parsed.buildId = value;
|
|
37
|
+
}
|
|
38
|
+
return parsed;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function runChromeCommand(argv, options = {}) {
|
|
42
|
+
const log = options.log ?? ((line) => console.log(line));
|
|
43
|
+
const error = options.error ?? ((line) => console.error(line));
|
|
44
|
+
const loadBrowsers = options.loadBrowsers ?? (() => import('@puppeteer/browsers'));
|
|
45
|
+
const homeDirectory = options.homeDirectory ?? homedir();
|
|
46
|
+
|
|
47
|
+
if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h'
|
|
48
|
+
|| (argv[0] === 'install' && (argv.includes('--help') || argv.includes('-h')))) {
|
|
49
|
+
log(usage);
|
|
50
|
+
return { exitCode: 0 };
|
|
51
|
+
}
|
|
52
|
+
if (argv[0] !== 'install') {
|
|
53
|
+
error(`不明なサブコマンドです: ${argv[0]}\n${usage}`);
|
|
54
|
+
return { exitCode: 2 };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = parseInstallArguments(argv, homeDirectory);
|
|
60
|
+
} catch (cause) {
|
|
61
|
+
error(`${cause instanceof Error ? cause.message : String(cause)}\n${usage}`);
|
|
62
|
+
return { exitCode: cause instanceof PublicError ? cause.exitCode : 1 };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let browsers;
|
|
66
|
+
try {
|
|
67
|
+
browsers = await loadBrowsers();
|
|
68
|
+
} catch (cause) {
|
|
69
|
+
error([
|
|
70
|
+
`@puppeteer/browsers を読み込めないため Chrome を導入できません: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
71
|
+
'システムの node がある場合は `npx puppeteer browsers install chrome` でも導入できます。',
|
|
72
|
+
].join('\n'));
|
|
73
|
+
return { exitCode: 1 };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const platform = browsers.detectBrowserPlatform();
|
|
78
|
+
const buildId = parsed.buildId
|
|
79
|
+
?? await browsers.resolveBuildId('chrome', platform, 'stable');
|
|
80
|
+
const installed = await browsers.install({
|
|
81
|
+
browser: 'chrome',
|
|
82
|
+
buildId,
|
|
83
|
+
cacheDir: parsed.cacheDir,
|
|
84
|
+
downloadProgressCallback: 'default',
|
|
85
|
+
});
|
|
86
|
+
if (typeof installed?.executablePath !== 'string' || installed.executablePath.length === 0) {
|
|
87
|
+
throw new Error('導入後の実行ファイルを特定できませんでした。');
|
|
88
|
+
}
|
|
89
|
+
log(`buildId: ${buildId}`);
|
|
90
|
+
log(`実行ファイル: ${resolve(installed.executablePath)}`);
|
|
91
|
+
return { exitCode: 0 };
|
|
92
|
+
} catch (cause) {
|
|
93
|
+
error(`Chrome の導入に失敗しました: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
94
|
+
return { exitCode: 1 };
|
|
95
|
+
}
|
|
96
|
+
}
|
package/src/cli.mjs
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
triggerBackgroundRefresh
|
|
23
23
|
} from './update-check.mjs';
|
|
24
24
|
import { applySelfUpdate, isRunningFromAppDir, rollbackSelfUpdate } from './self-update.mjs';
|
|
25
|
+
import { runChromeCommand } from './chrome-command.mjs';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* `akari` ランチャーの本体。3 入口契約(ターミナル `akari` / セッション内 `/akari` /
|
|
@@ -33,6 +34,8 @@ import { applySelfUpdate, isRunningFromAppDir, rollbackSelfUpdate } from './self
|
|
|
33
34
|
* options 経由で差し替え可能にしてあり、node --test から実プロセスを起動せずに分岐を検証できる。
|
|
34
35
|
*/
|
|
35
36
|
export async function run(args, options = {}) {
|
|
37
|
+
if (args[0] === 'chrome') return runChromeCommand(args.slice(1), options);
|
|
38
|
+
|
|
36
39
|
const log = options.log ?? ((line) => console.log(line));
|
|
37
40
|
const assets = options.assets ?? resolveLauncherAssets();
|
|
38
41
|
const scaffold = options.scaffold ?? defaultScaffold;
|
package/src/messages.mjs
CHANGED
|
@@ -303,6 +303,7 @@ export function describeCliHelp() {
|
|
|
303
303
|
' (引数なし) プロジェクトを開いて AI エージェントを起動(未作成なら自動作成)',
|
|
304
304
|
' store connect アカウント連携(無料の素材パックと購入済み素材が使えるようになる)',
|
|
305
305
|
' sounds 公式音源ライブラリを一括ダウンロード(無料)',
|
|
306
|
+
' chrome install 動画書き出しに使う Chrome をダウンロードして導入する',
|
|
306
307
|
' update [--force] 更新を確認する(--force で本体を入れ直す)',
|
|
307
308
|
' status 接続状態を確認する',
|
|
308
309
|
' migrate [dir] 古い edit.json を退避バックアップ付きで v2 へ変換',
|
|
@@ -42,6 +42,8 @@
|
|
|
42
42
|
"docs/contract-2026-08-18-v1-render-parity.md",
|
|
43
43
|
"docs/contract-2026-08-23-captions-emphasis-words-v0.md",
|
|
44
44
|
"docs/contract-2026-08-23-stroke-persistence.md",
|
|
45
|
+
"docs/contract-2026-08-28-osr-export-v0.md",
|
|
46
|
+
"docs/contract-2026-08-28-v2-audio-roles-v0.md",
|
|
45
47
|
"packages/akari-launcher/package.json",
|
|
46
48
|
"packages/akari-launcher/README.md",
|
|
47
49
|
"packages/akari-tools/package.json",
|
|
@@ -57,7 +59,10 @@
|
|
|
57
59
|
"packages/creator-root/package.json",
|
|
58
60
|
"packages/decision-cards/package.json",
|
|
59
61
|
"packages/decision-cards/README.md",
|
|
62
|
+
"packages/decision-log-report/package.json",
|
|
63
|
+
"packages/decision-log-report/README.md",
|
|
60
64
|
"packages/edit-lint/package.json",
|
|
65
|
+
"packages/edit-lint/README.md",
|
|
61
66
|
"packages/edit-store/package.json",
|
|
62
67
|
"packages/export-nle/package.json",
|
|
63
68
|
"packages/frame-engine/package.json",
|
|
@@ -67,6 +72,8 @@
|
|
|
67
72
|
"packages/intake-form/README.md",
|
|
68
73
|
"packages/matte-rvm/package.json",
|
|
69
74
|
"packages/media-bin/package.json",
|
|
75
|
+
"packages/osr-export/package.json",
|
|
76
|
+
"packages/osr-export/README.md",
|
|
70
77
|
"packages/overlay-runtime/package.json",
|
|
71
78
|
"packages/overlay-runtime/README.md",
|
|
72
79
|
"packages/pen-visuals/package.json",
|
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
"id": "n-0001", // 必須。^n-\d{4}$。edit.json 内で一意
|
|
40
40
|
"path": "out/narration/n-0001.mp3", // 必須。edit.json からの相対パス
|
|
41
41
|
"t": 12.5, // 必須。タイムライン秒。0 以上
|
|
42
|
+
"in": 5.8, // 任意。素材秒。省略時 0
|
|
43
|
+
"out": 9.7, // 任意。素材秒。省略時 素材末尾
|
|
42
44
|
"gain_db": 0, // 任意。既定 0。[-60, 12](bgm/sfx と同一。範囲外はエラー)
|
|
43
45
|
"script": "こんにちは、AKARI Videoです。", // 任意。表示原稿(人間が読む正本)
|
|
44
46
|
"reading": "こんにちわ、あかりびでおです。", // 任意。読み原稿(かな化後・生成に使った実テキスト)
|
|
@@ -63,6 +65,8 @@
|
|
|
63
65
|
| `audio.narration[].id` | string | 必須(要素内) | — | `^n-\d{4}$`。edit.json 内で一意 |
|
|
64
66
|
| `audio.narration[].path` | string | 必須(要素内) | — | edit.json からの相対(`audio.sfx[].path` と同一規約) |
|
|
65
67
|
| `audio.narration[].t` | number | 必須(要素内) | — | **タイムライン秒**(`audio.sfx[].t` / `overlays[].start` と同じ座標系)。0 以上 |
|
|
68
|
+
| `audio.narration[].in` | number | 否 | `0` | 素材秒。再生窓 `[in, out)` の始点。0 以上 |
|
|
69
|
+
| `audio.narration[].out` | number | 否 | 素材末尾 | 素材秒。再生窓 `[in, out)` の終点。0 より大きく `out > in` |
|
|
66
70
|
| `audio.narration[].gain_db` | number | 否 | `0.0` | dB。クランプ範囲 `[-60, 12]`(`audio.bgm` / `audio.sfx` と同一) |
|
|
67
71
|
| `audio.narration[].script` | string | 否 | — | 表示原稿(人間が読む正本。字幕連携等の元テキスト) |
|
|
68
72
|
| `audio.narration[].reading` | string | 否 | — | 読み原稿(かな化後・TTS 生成に実際に使ったテキスト) |
|
|
@@ -79,6 +83,14 @@
|
|
|
79
83
|
(ナレーションも `t` という 1 点情報を持つシーン単位の演出であり、BGM のような
|
|
80
84
|
「プロジェクト全体で 1 本」という制約は当てはまらない)。
|
|
81
85
|
|
|
86
|
+
### 1.1 ナレーション素材のトリム
|
|
87
|
+
|
|
88
|
+
`in` / `out` は `audio.sfx[]` と同じ素材秒の語彙を使う。再生区間は `[in, out)`、タイムライン上の
|
|
89
|
+
開始は従来どおり `t` とする。`in` 省略時は 0、`out` 省略時は素材末尾まで再生する。
|
|
90
|
+
`out <= in` は edit-lint が error とし、実尺との整合は render-cut が解決する。`in` が素材実尺以上なら
|
|
91
|
+
0 にクランプして warning、`out` が素材実尺を超えれば素材末尾へクランプして warning、クランプ後に
|
|
92
|
+
`out <= in` となる場合はその narration 要素だけを skip して warning とする。
|
|
93
|
+
|
|
82
94
|
## 2. パス解決規約
|
|
83
95
|
|
|
84
96
|
`audio.narration[].path` は `audio.bgm.path` / `audio.sfx[].path` と**同一規約**:
|
|
@@ -144,3 +144,24 @@ perspective のレイヤー分割フォールバック — perspective は `crop
|
|
|
144
144
|
- Chrome 不在、`.app` でない実行ファイル、`DevToolsActivePort` 待機または接続の失敗は、
|
|
145
145
|
「字幕レンダ用ブラウザの起動に失敗した」ことと Chrome の確認を日本語で示し、書き出しを
|
|
146
146
|
非 0 で停止する。別スタイルの簡易字幕へは切り替えない。
|
|
147
|
+
|
|
148
|
+
## 6. H.264 エンコーダ選択(2026-08-28 追記)
|
|
149
|
+
|
|
150
|
+
`--encoder` の語彙は `auto` / `videotoolbox` / `nvenc` / `qsv` / `amf` / `mf` / `x264` とする。
|
|
151
|
+
`master` 品質は x264 専用であり、ハードウェアエンコーダを明示した場合は拒否する。
|
|
152
|
+
|
|
153
|
+
| 値 | ffmpeg エンコーダ | 対応環境・品質制御 |
|
|
154
|
+
|---|---|---|
|
|
155
|
+
| `videotoolbox` | `h264_videotoolbox` | macOS。ビットレート制御 |
|
|
156
|
+
| `nvenc` | `h264_nvenc` | Windows / NVIDIA。VBR + CQ |
|
|
157
|
+
| `qsv` | `h264_qsv` | Windows / Intel。global quality |
|
|
158
|
+
| `amf` | `h264_amf` | Windows / AMD。CQP |
|
|
159
|
+
| `mf` | `h264_mf` | Windows Media Foundation。quality 0..100 |
|
|
160
|
+
| `x264` | `libx264` | 全環境。CRF |
|
|
161
|
+
|
|
162
|
+
`auto` は macOS で VideoToolbox → x264、Windows で NVENC → QSV → AMF → Media Foundation →
|
|
163
|
+
x264、その他の環境で x264 の順に解決する。ハードウェア対応は `ffmpeg -encoders` の一覧だけで
|
|
164
|
+
決めず、実際の1フレーム試し焼きにも成功した場合だけ採用する。Windows 向け4方式は最小解像度の
|
|
165
|
+
誤判定を避けるため 256x144 で試し焼きし、`AKARI_EXPORT_FORCE_X264=1` のときは試し焼きせず
|
|
166
|
+
すべて不採用とする。明示指定した Windows 向け方式が利用不能なら x264 へ暗黙移行せず停止する。
|
|
167
|
+
`AKARI_EXPORT_FORCE_X264=1` のときに Windows 向け方式を明示指定した場合も、同じく停止する。
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# analysis.json v0 人物マット(tracks.person_matte)データ契約
|
|
2
2
|
|
|
3
3
|
- 日付: 2026-07-23
|
|
4
|
+
- 改訂: 2026-08-27(§8 の format 席を開き mask_path / mask_format を追加)
|
|
4
5
|
- 状態: 実装ラウンドの SSOT(`tracks.person_matte` の値のみ確定)
|
|
5
6
|
- 前提: `contract-2026-07-17-data-contract-versioning.md`(版必須・追加のみ進化・明示マイグレの三原則)、
|
|
6
7
|
`contract-2026-07-13-m5-analysis-report.md`(`analysis.json` v0 の器と `tracks` の枠。
|
|
@@ -56,6 +57,8 @@
|
|
|
56
57
|
|
|
57
58
|
"person_matte": { // null(未生成)/ string(旧形)も有効
|
|
58
59
|
"path": "matte/person-matte.webm", // 必須。VP9 alpha WebM への相対 or 絶対パス
|
|
60
|
+
"mask_path": "matte/person-matte.mask.mp4", // 任意。追加のグレースケール H.264 マスク
|
|
61
|
+
"mask_format": "gray-h264-fullrange", // 任意。mask_path の形式
|
|
59
62
|
"fps": 24, // 必須。マット動画の fps(元素材と異なってよい)
|
|
60
63
|
"quality": "balanced", // 任意。fast / balanced / accurate / best を例示(enum 強制はしない)
|
|
61
64
|
"generated_at": "2026-07-23T01:33:30.069Z", // 任意。ISO8601
|
|
@@ -218,6 +221,7 @@ ffmpeg / ffprobe は OS の PATH 名を直接起動せず、`packages/media-bin`
|
|
|
218
221
|
|---|---|
|
|
219
222
|
| `packages/schemas/analysis.schema.json` | `$defs/personMatteTrack` として object 形の構造(`path` / `fps` の必須・型・範囲、`additionalProperties: false`)を定義し、`tracks.person_matte` から `null` / string / object の `oneOf` として参照する |
|
|
220
223
|
| 生成ヘルパー(`bin/person-matte/person-matte.mjs`) | 書き出した WebM が `codec_name = vp9` かつコンテナタグ `alpha_mode = 1` であることを ffprobe で確認してから成功を返す。アルファが落ちた出力を成功扱いにしない。タグキーの大文字小文字は書き込み経路によって変わりうるため、照合は大文字小文字非依存で行う |
|
|
224
|
+
| 追加マスク(`mask_path`) | `codec_name = h264`、`color_range = pc`、幅・高さ・`r_frame_rate`・`nb_frames` が VP9 alpha WebM と一致し、`start_pts = 0` であることを ffprobe で確認する |
|
|
221
225
|
| `skills/analyze-footage/analysis-json.md` の意味制約 | JSON Schema で表せない条件(`path` が解決でき実ファイルがある、マット動画の時刻 0 が素材の時刻 0 と一致する、`fps` がマット動画の実 fps と一致する)を確定前に人が検査する |
|
|
222
226
|
|
|
223
227
|
**`analysis.json` 専用の検証 CLI は本契約では新設しない。** `packages/schemas/bin/` には
|
|
@@ -242,6 +246,27 @@ JSON として読めるかまでしか見ていない(`analysis.schema` チェ
|
|
|
242
246
|
いずれも別契約で扱う。本契約は `tracks.person_matte` の器だけを確定し、これらの席が将来開く
|
|
243
247
|
可能性があることを記録するに留める。
|
|
244
248
|
|
|
249
|
+
### 8.1 `mask_path` / `mask_format`(2026-08-27 追加)
|
|
250
|
+
|
|
251
|
+
§8 の `format` の席を、VP9 alpha WebM を置換しない追加出力として開く。`path` が指す VP9 alpha
|
|
252
|
+
WebM の生成と既存消費は不変であり、`mask_path` は v2 frame-engine がハードウェアデコード可能な
|
|
253
|
+
グレースケールマスクを使うための追加物である。
|
|
254
|
+
|
|
255
|
+
| 項目 | 規格 |
|
|
256
|
+
|---|---|
|
|
257
|
+
| コンテナ / codec / profile | mp4 / H.264(`libx264`)/ High |
|
|
258
|
+
| 画素 | `yuv420p`、Y = アルファ(0 = 透明、255 = 不透明)、U/V = 128 |
|
|
259
|
+
| レンジ・色タグ | full range(`color_range=pc`)、BT.709 primaries / transfer / colorspace |
|
|
260
|
+
| GOP・品質 | GOP 1 秒以下、`crf 6`、`preset medium`、B frame なし |
|
|
261
|
+
| 時間 | 解像度・fps・尺・フレーム数はカラー元と一致し、先頭 PTS は 0 |
|
|
262
|
+
| 命名 | `<VP9 alpha WebM の basename>.mask.mp4` |
|
|
263
|
+
|
|
264
|
+
`mask_format` の現行値は `"gray-h264-fullrange"` とする。`mask_path` の相対パスは `path` と同じく
|
|
265
|
+
**analysis.json の所在ディレクトリ**を基準に解決し、区切りは `/` を使う。
|
|
266
|
+
|
|
267
|
+
`mask_path` が無い、または解決・検証できない場合、消費側は `path` の VP9 alpha WebM から一度だけ
|
|
268
|
+
同規格のマスクへ取り込み変換する。それも失敗した場合は人物演出を諦め、映像本体の処理は止めない。
|
|
269
|
+
|
|
245
270
|
## 9. 既知の追随事項(本契約が作る宿題)
|
|
246
271
|
|
|
247
272
|
- **`packages/analysis-report`** の軽量チェックは `tracks.person_matte` を「string か null」に
|
|
@@ -249,6 +274,7 @@ JSON として読めるかまでしか見ていない(`analysis.schema` チェ
|
|
|
249
274
|
本タスクのファイル境界外のため未修正。object 形を実運用へ載せる前に、この読み手を
|
|
250
275
|
`oneOf` へ追随させる必要がある(表示側の「人物マット: あり / なし」の判定も
|
|
251
276
|
`tracks.person_matte` の真偽値で動くため、object 形でもそのまま「あり」になる)
|
|
277
|
+
- `packages/analysis-report` は object 形と `quality` / マスク併産の表示へ追随済み(2026-08-28)
|
|
252
278
|
- **`<video>` の時刻同期が未実装**である(`packages/overlay-runtime`)。したがって
|
|
253
279
|
「動く人物の text-behind-person」は本契約が整っても**まだ本番品質ではない**。
|
|
254
280
|
マットが取れることと、それを本番の合成として出せることは別である
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
- `sfxItem` に optional `in` / `out` を追加(**素材秒**。`in` ≥ 0 省略時 0、
|
|
32
32
|
`out` > `in` 省略時 素材末尾)。再生区間 = 素材の [in, out)、
|
|
33
33
|
タイムライン上の開始は従来どおり `t`(timeline 秒)、表示尺 = out − in
|
|
34
|
+
- `narrationItem` にも同じ optional `in` / `out` を追加する。再生区間・素材秒・既定値・
|
|
35
|
+
`out > in` の検証分担は sfx と同一で、タイムライン上の開始は narration の `t` とする
|
|
34
36
|
- `bgm` に optional `in` を追加(BGM ファイル内の開始オフセット素材秒。ループ・全体尺
|
|
35
37
|
トリムの既存意味論は不変)
|
|
36
38
|
- edit-lint: `out <= in` を error。実尺越えの検知は lint では行わない
|
|
@@ -40,6 +42,12 @@
|
|
|
40
42
|
### 消費(render-cut + preview)
|
|
41
43
|
|
|
42
44
|
- render-cut: sfx の [in, out) 切り出しを出力に反映。bgm の `in` オフセット反映
|
|
45
|
+
- render-cut: narration の [in, out) 切り出しも出力に反映する。`in` が素材実尺以上なら 0 へ、
|
|
46
|
+
`out` が素材実尺を超えれば素材末尾へクランプして warning を出す。クランプ後に `out <= in` なら
|
|
47
|
+
その narration 要素だけを skip する。`in` / `out` の有無にかかわらず、各 narration 要素は
|
|
48
|
+
デコード可否の判定を兼ねて実尺を従来と同じ 1 回だけ probe し、デコードできなければ従来どおり
|
|
49
|
+
その要素だけを skip して warning を出す一方、両方省略された要素には `atrim` を前置きせず、
|
|
50
|
+
従来とバイト同一のフィルタ文字列を保つ
|
|
43
51
|
- preview(previewAudio): 同意味論で再生。実尺越え in/out は素材末尾へクランプ
|
|
44
52
|
|
|
45
53
|
### UI
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# ページ全体 OSR 書き出し v0 契約
|
|
2
|
+
|
|
3
|
+
## 1. 適用範囲
|
|
4
|
+
|
|
5
|
+
この契約は `render-cut --engine osr` が生成する映像ページと、そのページを Electron オフスクリーン描画で駆動するプロトコルを定める。既定の engine は `legacy` であり、OSR は opt-in とする。
|
|
6
|
+
|
|
7
|
+
## 2. ページ契約
|
|
8
|
+
|
|
9
|
+
ページは出力幅 `W`、映像高 `H` に検証用1行を加えた `W × (H + 1)` で構成する。映像領域の重ね順は下から次の4層である。
|
|
10
|
+
|
|
11
|
+
1. frame-engine canvas。cuts、layers、transition、matte、LUTを評価する。
|
|
12
|
+
2. `captions.json` から生成したDOM字幕。
|
|
13
|
+
3. `edit.json` の自由HTML。
|
|
14
|
+
4. 自由HTML内のThree.js canvas。
|
|
15
|
+
|
|
16
|
+
字幕、自由HTML、3Dは render-cut と同じ overlay sheet 生成器により、透明な同一オリジン iframe として canvas 上へ置く。無効なトラックは最初からDOMへ入れず、活性区間ごとのDOM再構築は行わない。
|
|
17
|
+
|
|
18
|
+
ページは次のAPIを公開する。
|
|
19
|
+
|
|
20
|
+
- `window.__akariReady`: フォント、画像、動画、3D、frame-engineのprime完了を表すPromise。
|
|
21
|
+
- `window.__akariSeek(seconds, frameNumber)`: frame-engine評価、overlay sheetのシーク、スタンプ更新、2回の`requestAnimationFrame`待機を順に完了する。
|
|
22
|
+
- `window.__akariSettle()`: 検証不一致時に2回の`requestAnimationFrame`を進める。
|
|
23
|
+
|
|
24
|
+
CSS animationはpauseし、`currentTime`を合成時刻へ設定する。Three.jsは対象区間のローカル時刻で描画する。動画要素は提示フレームの確定まで待つ。`frameNumber`はmainから明示的に渡し、秒から再計算しない。
|
|
25
|
+
|
|
26
|
+
## 3. スタンプ行
|
|
27
|
+
|
|
28
|
+
最下1行はフレーム番号 `n mod 65536` を次で符号化する。
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
R = n & 255
|
|
32
|
+
G = (n >> 8) & 255
|
|
33
|
+
B = 0x55
|
|
34
|
+
A = 255
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
BGRA bitmapでは `[0x55, G, R, 255]` となる。左端、中央、右端の3画素を復号し、期待番号との全点一致を要求する。確認後、ffmpegへ渡す前に `buffer.subarray(0, W * H * 4)` で最下行を除く。
|
|
38
|
+
|
|
39
|
+
`--verify stamp|hash|off` を持ち、既定は `stamp` とする。`hash` は直前の映像領域と同じSHA-256ならsettle後に再取得し、静止画で上限へ達した場合は曖昧件数を記録して受理する。`off` は比較計測用である。通常書き出しではverifyを無効にしない。
|
|
40
|
+
|
|
41
|
+
## 4. 駆動プロトコル
|
|
42
|
+
|
|
43
|
+
各コマは次の順で処理する。
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
seek → ready → invalidate → paint → verify → write
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`paint`が既定10秒以内に届かなければ失敗として記録する。bitmapは必ず `W × (H + 1)` と照合する。不一致時はsettleして再度`invalidate`し、最大8回で停止する。
|
|
50
|
+
|
|
51
|
+
映像領域のBGRAは深さ3を既定とするbounded queueへ渡す。ffmpeg stdinの`write()`がfalseなら必ず`drain`を待つ。無制限のpre-bufferは禁止する。v0は先頭から末尾まで連番1 workerで評価する。
|
|
52
|
+
|
|
53
|
+
`run.json` はseek、paint、toBitmap、verify、writeのp50/p95、1000コマ区切りmedian、先頭と末尾のdriftRatio、paint timeout、verify retry、verify前delta histogram、backpressure、メモリ、ffprobe結果を記録する。
|
|
54
|
+
|
|
55
|
+
## 5. LUT
|
|
56
|
+
|
|
57
|
+
`output.look` のLUTはframe-engine canvas内のsampler3Dで適用する。ページ全体へCSS filterを掛けない。したがって字幕、自由HTML、3DはLUTの外にあり、映像canvasだけが色変換の対象となる。
|
|
58
|
+
|
|
59
|
+
## 6. Electronの器
|
|
60
|
+
|
|
61
|
+
起動は次の3段で解決する。
|
|
62
|
+
|
|
63
|
+
1. インストール済みAKARI VideoのElectron実行体を`--render`付きで再利用する。
|
|
64
|
+
2. npm optionalDependencyの`electron`を使う。`dist`のライセンス2ファイル、version、プラットフォーム実行体が揃うことを検査する。
|
|
65
|
+
3. Electronが無ければ警告を出し、現行render-cut経路へフォールバックする。
|
|
66
|
+
|
|
67
|
+
第1段・第2段とも、実プロセスのコマンドラインに`--force-device-scale-factor=1`、`--force-color-profile=srgb`、background throttling無効化スイッチを渡す。npm Electronではスクリプトパスを`argv[1]`に保ち、その後へChromiumスイッチを置く。ソフト描画時は加えてGPU無効化とSwiftShaderスイッチを渡す。
|
|
68
|
+
|
|
69
|
+
パッケージ版のTheiaではelectron-main contributionが`--render`を捕捉する。contribution開始は初期ウィンドウ表示とbackend起動の後なので、v0ではスプラッシュが一瞬表示され得る。通常起動で`--render`が無い場合、contributionは何もしない。
|
|
70
|
+
|
|
71
|
+
Linux v0は第3段を使用する。将来の差し替え席として、Chrome headlessと`HeadlessExperimental.beginFrame`を使うlauncherを第1段と第2段の間へ追加できるものとする。この契約では実装しない。
|
|
72
|
+
|
|
73
|
+
## 7. エンコード、音声、照合
|
|
74
|
+
|
|
75
|
+
ffmpeg入力は `-f rawvideo -pixel_format bgra -video_size WxH -framerate fps -i -` とする。品質とエンコーダはrender-cutの`master|high|standard|light`および`auto|videotoolbox|x264`を使用する。映像は1世代だけH.264へ圧縮し、その後の音声処理とmuxでは映像をcopyする。
|
|
76
|
+
|
|
77
|
+
ffprobe timeoutは `max(120000, frames × 100)` msとする。尺、フレーム数、解像度をplanと照合する。
|
|
78
|
+
|
|
79
|
+
## 8. メモリと長尺
|
|
80
|
+
|
|
81
|
+
- GPU描画の警戒線: 768 MiB / export、hard stop: 1,024 MiB / export。
|
|
82
|
+
- ソフト描画(SwiftShader)は1080pで1.1 GiB台に達するため、警戒線1,536 MiB / hard stop 2,048 MiBの別枠を使う。
|
|
83
|
+
- `AKARI_OSR_MEMORY_WARN_MIB` / `AKARI_OSR_MEMORY_HARD_STOP_MIB`で正の整数MiBへ上書きでき、適用値はwarning < hard stopを必須とする。
|
|
84
|
+
- 並列予算1 worker = 1 GiBはGPU前提の値である。v0のworker数は1。
|
|
85
|
+
- 10秒ごとにRSSを記録し、ウィンドウ破棄後も採る。
|
|
86
|
+
- 固定Nコマごとのページ再生成は行わない。再生成を許すのはページ境界、renderer crash、watchdog回復時だけである。
|
|
87
|
+
|
|
88
|
+
非連番seekは描画履歴が変わり得るため、チャンク分割・並列化はbyte再現モードと両立しない。将来導入する場合は先頭からのwarm-up履歴または完成画の別検収を必要とする。
|
|
89
|
+
|
|
90
|
+
## 9. 検収
|
|
91
|
+
|
|
92
|
+
CIはソフト描画の連番2走について全コマSHA-256一致を要求する。製品はGPUを既定とし、同一マシン2走の一致率、`differingPixels`、`maxDelta`を診断値として記録する。GPUのbyte-exactは合否条件にしない。差分調査はH.264を再デコードした画像ではなく、捕捉時のraw BGRAを使用する。
|
|
93
|
+
|
|
94
|
+
legacyとの比較は字幕、自由HTML、3Dの各指定時刻についてMADと`differingPixels`を記録する。
|
|
95
|
+
|
|
96
|
+
## 10. 使用しない中間規律
|
|
97
|
+
|
|
98
|
+
OSR経路では次を使用しない。
|
|
99
|
+
|
|
100
|
+
- アルファ付き中間動画。
|
|
101
|
+
- PNG連番。
|
|
102
|
+
- ffmpeg overlay。
|
|
103
|
+
- 二重の映像エンコード。
|
|
104
|
+
- 3Dの別キャプチャ。
|
|
105
|
+
- 字幕の活性区間ごとのDOM再構築。
|
|
106
|
+
- 静止コマの重複除去。
|
|
107
|
+
- 固定Nコマごとのページ再生成。
|
|
108
|
+
|
|
109
|
+
## 11. 既知の限界
|
|
110
|
+
|
|
111
|
+
### 11.1 Bフレーム素材の並べ替え遅延
|
|
112
|
+
|
|
113
|
+
負のDTSで始まるBフレーム素材では、エンジンのデコード経路が並べ替え遅延ぶん手前のコマを返す。`has_b_frames=2`の1920×1080 / 30fps素材では、先頭コマだけが一致し、その後は一定2コマ手前になることを実測した。同一素材を`-bf 0`で生成するとlegacyと完全に一致する。v0はこのずれを補正しない。
|
|
114
|
+
|
|
115
|
+
### 11.2 legacyとの全画面画素差
|
|
116
|
+
|
|
117
|
+
同じraw BGRAを比較した場合、ffmpegが未タグ素材へ既定で使うbt601換算に対してMAD 9.28 / maxDelta 155、bt709換算に対してMAD 0.886であった。残差はクロマ補間による。エンジンは`bt709-limited`で合成する。
|
|
118
|
+
|
|
119
|
+
ベースを単色にしたfixtureでlegacyとOSRの最終MP4を比較すると、MAD 0.019〜0.345 / maxDelta 7〜78であった。字幕・自由HTML・3Dの描画は一致し、全画面差の主因はベース映像のYUV→RGB変換である。オーバーレイ層の突き合わせは単色ベースで行う。
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# v2 音声処理の役割分担 v0 — Web Audio プレビューと ffmpeg マスター
|
|
2
|
+
|
|
3
|
+
- 日付: 2026-08-28
|
|
4
|
+
- 状態: draft(L1 実測値を反映済み)
|
|
5
|
+
- 前提: `contract-2026-07-14-edit-json-v1-audio.md`、
|
|
6
|
+
`contract-2026-07-20-edit-json-v1-narration.md`、
|
|
7
|
+
`contract-2026-07-25-r6-audio-tracks-and-trim.md`
|
|
8
|
+
- スコープ: frame-engine 評価台における BGM / narration / SFX のプレビュー供給と、
|
|
9
|
+
render-cut による最終書き出し音声の責務境界
|
|
10
|
+
|
|
11
|
+
## 1. 役割分担
|
|
12
|
+
|
|
13
|
+
**プレビューは Web Audio による近似、書き出しは ffmpeg マスター処理による正
|
|
14
|
+
(authoritative)**とする。
|
|
15
|
+
|
|
16
|
+
frame-engine 評価台は、解決済みタイムライン尺と edit.json の音声宣言、デコード済み素材実尺から
|
|
17
|
+
決定論的な予定表を作り、`AudioBufferSourceNode` と `GainNode` へ供給する。再生中は
|
|
18
|
+
`AudioContext.currentTime` をクロックの正として映像描画を追従させる。同じ予定表は
|
|
19
|
+
`OfflineAudioContext` でも再生でき、実時間プレビューと比較用オフライン描画の入力を一致させる。
|
|
20
|
+
|
|
21
|
+
render-cut は最終成果物の音声品質を決める唯一の正である。プレビューで聴こえた結果を、
|
|
22
|
+
ラウドネス、true peak、ノイズ処理、動的 ducking を含む納品音声の保証には使わない。
|
|
23
|
+
|
|
24
|
+
## 2. 近似の一覧
|
|
25
|
+
|
|
26
|
+
| 項目 | プレビュー(Web Audio) | 書き出し(ffmpeg) | 差の性質 |
|
|
27
|
+
|---|---|---|---|
|
|
28
|
+
| ducking | narration の実効区間を矩形エンベロープ化し、区間内をカーネル既定の固定減衰にする | narration を主、素材ダイアログを fallback の sidechain とする `sidechaincompress` | プレビューは発話レベルに反応せず、attack / release も持たない。master 無しの実測差は 1.67 dB(§3.2) |
|
|
29
|
+
| BGM fade | タイムライン上の `fadeIn` / `fadeOut` を線形 `AudioParam` automation にする | `afade` をマスター音声チェーン内で適用する | master 無しの実測差は ±0.034 dB 以内(§3.2)。後段処理後の振幅は一致しない場合がある |
|
|
30
|
+
| SFX fade | クリップ実効尺に対する `fade_in` / `fade_out` を線形 automation にする | trim 後の実効尺へ `afade` を適用する | 基本形状は同じ。後段マスター処理の影響は書き出しだけに生じる |
|
|
31
|
+
| ラウドネス | 個別 gain と fade / ducking の合成のみ。番組全体の規格化はしない | EBU R128 計測とマスター処理を適用する | I / LRA / TP は一致を保証しない |
|
|
32
|
+
| BGM ループ境界 | `AudioBufferSourceNode.loop`。初回 `in` 後は素材先頭へ戻る | ffmpeg の loop 入力を最終尺でクランプする | デコーダ境界、サンプル丸め、クリック抑制の実装差が残り得る |
|
|
33
|
+
| trim | デコード実尺へ `in` / `out` をクランプし、開始 offset と再生 duration に変換する | probe 実尺へクランプして `atrim` / timestamp リセットを行う | 同じ素材秒を狙う。デコード実尺やサンプル境界の差だけを近似として許容する |
|
|
34
|
+
| SFX の重なり | 各イベントを独立した BufferSource として同時接続する | 各イベントを遅延後に `amix normalize=0` で合成する | 多重入力時のピークと後段保護処理に差が出る |
|
|
35
|
+
| gain | `gain_db` を範囲内へクランプし、`10^(dB/20)` で線形 gain にする | 同じ dB 指定を `volume` へ渡す | 基礎変換は同じ。マスター処理後の絶対振幅は ffmpeg が正 |
|
|
36
|
+
| afftdn | 適用しない | マスター処理の構成に応じて適用する | ノイズ床と高域成分は書き出しだけ変化する |
|
|
37
|
+
| loudnorm / true peak guard | 適用しない | 出力ポリシーに従い適用する | 最終音量、LRA、true peak は書き出しだけが保証する |
|
|
38
|
+
|
|
39
|
+
## 3. L1 実測
|
|
40
|
+
|
|
41
|
+
測定には同じ edit.json と決定論的なトーン素材を用いる。BGM を 200 Hz、narration を
|
|
42
|
+
3000 Hz とし、混合結果の 200 Hz 帯を分離して BGM の減衰軌跡を測る。プレビュー側は
|
|
43
|
+
`OfflineAudioContext`、書き出し側は render-cut の成果物を入力とする。ラウドネスは両方を
|
|
44
|
+
ffmpeg `ebur128=peak=true` で測る。
|
|
45
|
+
|
|
46
|
+
### 3.1 同期
|
|
47
|
+
|
|
48
|
+
環境は macOS 26.2 / Chromium(Playwright)、フィクスチャは総尺 300 s / 30 fps / cuts 300 /
|
|
49
|
+
narration 10 / SFX 20 / BGM 1(ducking on)とした。本表は Web UI 評価台の実測である。
|
|
50
|
+
shell 評価台も同名の観測窓(`window.akariFrameEngineAudioDebug()`)で同じ量を採取できる。
|
|
51
|
+
|
|
52
|
+
| 条件 | サンプル間隔 | サンプル数 | 最大ドリフト (ms) | p95 (ms) | 判定上限 (ms) |
|
|
53
|
+
|---|---:|---:|---:|---:|---:|
|
|
54
|
+
| 5 分通し再生 | 10 s | 29 | 2.700 | 2.700 | 33 |
|
|
55
|
+
| 30 回シーク後 | 各シーク後 | 30 | 16.667 | 6.666 | 33 |
|
|
56
|
+
|
|
57
|
+
ドリフトは「最後に描画完了したフレームのタイムライン秒 − AudioContext 由来の再生位置」を
|
|
58
|
+
ms へ換算し、絶対値で集計する。全 59 点の最大は 16.667 ms、p95 は 6.666 ms だった。
|
|
59
|
+
通し再生の 29 点は全点 2.700 ms で一定であり、時間とともに増える発散成分は観測されなかった。
|
|
60
|
+
`scheduleStartAtSec` は 0.0293 s、5 分走り切った時点の `wallClockOffsetSec` は 0.0224 s だった。
|
|
61
|
+
|
|
62
|
+
### 3.2 プレビューと書き出しの差
|
|
63
|
+
|
|
64
|
+
| 測定項目 | 単位 | プレビュー | 書き出し: master 無し | 差: preview − master 無し | 書き出し: master あり | 差: preview − master あり |
|
|
65
|
+
|---|---:|---:|---:|---:|---:|---:|
|
|
66
|
+
| narration 区間の BGM 減衰 | dB | -11.628 | -9.956 | -1.672 | -27.639 | +16.010 |
|
|
67
|
+
| fade-in 0.5 s 地点(plateau 比) | dB | -12.021 | -11.992 | -0.029 | -8.383 | -3.638 |
|
|
68
|
+
| fade-in 1.5 s 地点(plateau 比) | dB | -2.512 | -2.516 | +0.004 | +1.085 | -3.597 |
|
|
69
|
+
| fade-out 残り 1.5 s 地点(= 10.5 s・plateau 比) | dB | -2.467 | -2.471 | +0.004 | -24.571 | +22.104 |
|
|
70
|
+
| fade-out 残り 0.5 s 地点(= 11.5 s・plateau 比) | dB | -11.890 | -11.856 | -0.034 | -33.081 | +21.191 |
|
|
71
|
+
| Integrated loudness (I) | LUFS | -12.3 | -12.3 | 0.0 | -14.3 | +2.0 |
|
|
72
|
+
| Loudness range (LRA) | LU | 11.5 | 11.5 | 0.0 | 5.7 | +5.8 |
|
|
73
|
+
| True peak (TP) | dBFS | -11.9 | -14.7 | +2.8 | -10.7 | -1.2 |
|
|
74
|
+
|
|
75
|
+
`master 無し` は ducking / fade を含む素のミックス差、`master あり` は
|
|
76
|
+
`denoise: off` / `loudnorm: -14` を加えた納品側の差を表す。差の大小をこの版で合否条件にはせず、
|
|
77
|
+
測定が成立したことと、同期の 33 ms 上限だけを機械判定する。
|
|
78
|
+
|
|
79
|
+
1. **fade 形状は master 無しなら実質一致する。** 全 4 点で差は絶対値 0.034 dB 以下で、
|
|
80
|
+
測定ノイズ相当だった。プレビューの線形 `AudioParam` ランプと ffmpeg `afade` は、時刻も
|
|
81
|
+
曲線も揃っている。
|
|
82
|
+
2. **ducking の深さは master 無しで 1.67 dB 異なる。** プレビューの固定 -12 dB のほうが深い。
|
|
83
|
+
`sidechaincompress` は attack 5 ms / release 300 ms・ratio 8 の圧縮であり、区間平均では
|
|
84
|
+
-12 dB まで沈み切らない。この差を §4.1 の判断材料とする。
|
|
85
|
+
3. **master ありの相対 dB は 1-pass `loudnorm` の時変ゲインで汚染される。** `loudnorm` は
|
|
86
|
+
区間ごとにゲインを動かすため、plateau 比という尺度そのものが成立しなくなる。fade-out 側の
|
|
87
|
+
-24 dB / -33 dB は BGM 自体の減衰量ではない。この列で意味を持つのは I / LRA / TP の 3 行で、
|
|
88
|
+
fade / ducking 行はマスター処理後に相対測定が使えなくなることの証拠として読む。
|
|
89
|
+
4. **ラウドネスは master 無しなら I / LRA が完全一致する。** TP の 2.8 dB 差は書き出しが
|
|
90
|
+
AAC 再エンコードを通るためである。master ありでは I が目標 -14 LUFS へ寄り、LRA は
|
|
91
|
+
11.5 LU から 5.7 LU へ圧縮された。プレビューがラウドネスを保証しないことの数値的な裏付けとなる。
|
|
92
|
+
|
|
93
|
+
## 4. G3 までに詰める項目
|
|
94
|
+
|
|
95
|
+
1. ducking の BGM 減衰差と attack / release の差を実測し、矩形近似を残すか、カーネルが
|
|
96
|
+
計算する共通エンベロープを両側で消費するかを決める。共通化する場合でも、最終的な
|
|
97
|
+
compressor / limiter の裁定権は ffmpeg 側に残す。
|
|
98
|
+
2. fade の相対曲線が許容差に収まるか確認する。時刻が一致して振幅だけがマスター処理由来で
|
|
99
|
+
異なる場合は近似として残す。時刻差がある場合は G3 前に予定表または ffmpeg filter 順を直す。
|
|
100
|
+
3. ループ境界と trim 境界でクリック、1 サンプル以上の空隙、意図しない重複がないかを追加測定する。
|
|
101
|
+
4. SFX 多重時の true peak を測り、プレビューへ軽量な保護を入れるか、書き出し確認を必須のままに
|
|
102
|
+
するかを決める。プレビュー側で loudnorm を再実装することはしない。
|
|
103
|
+
5. I / LRA / TP の差を UI で明示する必要があるか判断する。少なくとも G3 時点でも
|
|
104
|
+
「プレビューは近似、最終音声は書き出しで確認」の表示を維持する。
|
|
105
|
+
|
|
106
|
+
## 5. 残す近似
|
|
107
|
+
|
|
108
|
+
- Web Audio と ffmpeg のデコーダ、サンプル境界、出力デバイスの差
|
|
109
|
+
- プレビューで afftdn / loudnorm / true peak guard を実行しないこと
|
|
110
|
+
- プレビュー ducking を固定区間で表すこと。ただし §3 の差が G3 の許容範囲を超える場合は、
|
|
111
|
+
§4.1 の共通エンベロープ案を採用してから G3 へ進む
|
|
112
|
+
- 聴感確認の即時性を優先し、プレビューでは最終マスター処理の計算コストを負わないこと
|
|
113
|
+
|
|
114
|
+
これらの近似を残しても、タイムライン上の開始、trim、loop、gain、fade、ducking 対象区間は
|
|
115
|
+
同じ決定論的予定表から再現できなければならない。
|
|
@@ -52,6 +52,20 @@ DL・sha256 検証・適用まで実行。それ以外(npm グローバル / g
|
|
|
52
52
|
`packages/asset-resolver` の CLI への薄い委譲で、カタログ合成・entitlements 判定・
|
|
53
53
|
sha256 検証・fail-closed は resolver 側の責務のまま。`src/assets-command.mjs`)。
|
|
54
54
|
|
|
55
|
+
### Chrome の導入
|
|
56
|
+
|
|
57
|
+
動画の書き出しに使う Chrome for Testing は、次のコマンドで導入できる。
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
akari chrome install
|
|
61
|
+
akari chrome install --cache-dir /path/to/cache
|
|
62
|
+
akari chrome install --build-id 150.0.7339.16
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
保存先の既定は `~/.cache/puppeteer`。`--cache-dir` で保存先、`--build-id` で導入する
|
|
66
|
+
buildId を指定できる。実行環境から `@puppeteer/browsers` を解決できる必要があり、
|
|
67
|
+
AKARI Video アプリの配布物には必要なモジュールが同梱されている。
|
|
68
|
+
|
|
55
69
|
`akari` に渡した引数はそのまま `opencode` に転送する(例: `akari --continue` は
|
|
56
70
|
`opencode --continue` を起動する)。
|
|
57
71
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "AKARI Video launcher CLI — start an AI-edited video project from any directory: scaffold, connection check, then hand over to Claude Code (or opencode). AKARI Video を opencode や Claude Code で、どのディレクトリからでも始めるための `akari` ランチャー CLI。接続確認(doctor)→ 未セットアップならプロジェクト雛形を作成 → AI エージェントを起動する。外部 npm 依存ゼロ(Node.js 組み込みモジュールのみ)。 [akari-video npm vendor: bin/akari.mjs is reference-only. These CLI entrypoints are not included in the akari-video npm package. Run them from a full AKARI Video app installation (normally ~/.akari/app) or a monorepo checkout.]",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|