Releases: DeepRegular/SmartCut
Release list
SmartCut v0.7.0
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.7.0 は 1 枚に入りきらない録画を収める版である。1 時間番組を 6 本も録れば 30 GB になり、片面 1 層のディスクは 25 GB しか入らない。これまでの解決策は「どれか 1 本を諦める」だった。いまは映像だけを書き直して収める。1 フレームもデコードしない。 GOP も動きベクトルもタイムスタンプも、音声も字幕も番組情報も、届いたままである。収まるときは何もしない。
あわせて、BDAV ディスクを書くときにデータ放送を「運ぶ」と言っていたのに運んでいなかったのを直した。ほかに直したのは表示と文言で、カットの仕上がりが変わるものは無い。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.7.0_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.7.0-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.7.0_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。4.0MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.7.0_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.7.0.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
係数だけを減らして、書き戻す
rust/crates/mpeg2 はデコーダでもエンコーダでもない。**コード化されたピクチャを係数のところまで読みほどき、残りはビット単位でそのまま写して書き戻す。**逆変換も動き補償も無い。**デコードしないから速い。**10 分の録画を全部書き直して 30 秒、そのままコピーすれば 6 秒である。再エンコードなら、この比ではない時間がかかる。
係数に対してすることは 2 つある。効くのは 2 つ目のほうである。
ひとつは量子化スケールを上げること。放送が使う非線形スケールではコード 1 つが倍なので、1 つのコードを 2 つのコードと割合に分け、どちらをどのマクロブロックに当てるかは黄金比で分散させる。もうひとつはブロック末尾の係数を切り捨てることで、画質への寄与(レベル × 量子化行列の重みの 2 乗)より、その係数自身のコードのビット数のほうが高くつくなら捨てる。
1440x1080 の放送 1 分で測った。
| 映像の大きさ | Y-PSNR 平均 | |
|---|---|---|
| 量子化スケールを上げるだけ | 0.739 | 42.0 dB |
| 2 つを併用(実装) | 0.759 | 48.3 dB |
**量子化スケールを上げるだけのほうが、小さくて 6 dB 悪い。**同じ素材を同じ大きさに書かせた比較では、参照したツールの 46.4 dB に対して 48.3 dB、最悪のフレームは 40.4 dB に対して 42.7 dB だった。
割合は 1 枚ずつではなく録画全体に当てる。 1 枚を自分自身の何割かに強制すると、そのピクチャが GOP の中で持っていた役割が消える。GOP の頭の I ピクチャを、そこからぶら下がる B ピクチャと同じ割合で潰すのは、いちばん効かないところにいちばん使うということだ。だから実行中の量子化スケールは一定に保ち、録画自身のビット配分には触らない。動かすのは、ここまでのピクチャが予定に対していくら使いすぎたかという残高だけである。放送 1 分を 0.7557 で指定して、0.7594 で返ってきた。
代償はドリフトである。デコーダが組み立て直す参照画像は、ここで丸めた係数でできているので少し違う。その差は補正されずに GOP の中で積み上がり、次のイントラピクチャで消える。速い方式はどれもこれを払っていて、参照したツールも同じ鋸歯を描く。緩めの圧縮で、GOP の両端の差は 5 dB ほどである。
何割にすればよいかは、書き出す前に画面で分かる
出力設定の BDAV 出力タブにディスクの使用量が出る。録画 1 本ずつを帯にして、選んだディスクに対してどれだけかを描く。白い線がディスクの端、その手前の細い線が残しておく 1%、越えた部分は赤くなる。トランスコードするを入れると、その下に「変換後」の帯が増え、映像を何割で書くかが出る。
やっているのはレートの計算だけで、ファイルは読み直さない。映像のレートは録画を読み込んだときに測った値、音声のレートは宣言された値。それぞれに「残す長さ」を掛け、多重化のオーバーヘッド(192 バイトのパケット、ピクチャごとの PES ヘッダ、毎フレームのテーブル、クリップの索引、196,608 バイト単位のパディング)を足す。範囲を動かすたびに計算し直しても、録画を開き直さない。
丸ごと 1 本をディスクに書く場合の誤差は 1% ほどである。
| 見積もり | 実際 | |
|---|---|---|
| 50 分 | 5,114 MB | 5,147 MB |
| 45 分 | 3,711 MB | 3,699 MB |
35% を下回らないと入らない一覧は、書き出さずにその旨を表示する。そこまで下げると、もう同じ映像の小さい版ではないからである。
コマンドラインからは --fit bd25|bd50|bd100|bd128|バイト数、割合を直接指定するなら --video-share 0.35..1。
70 万フレームのバイト比較
MPEG-2 を正しく読めている証拠は 1 つしかない。読みほどいて何もせずに書き戻したピクチャが、届いたピクチャとバイト単位で同じであることである。マクロブロックのすべての欄を読んだ値から書き直しているので、テーブルの 1 行が間違っていても、長さの数え方が 1 ビットずれていても、違うバイトとして出る。
| 枚数 | 不一致 | 読めず | |
|---|---|---|---|
| 8 局・各 30 分 | 425,452 | 0 | 7 |
| ディスクから読んだ 50 分 | 89,899 | 0 | 0 |
| それを参照ツールが書き直したもの | 106,082 | 0 | 0 |
| それを SmartCut が切ったもの | 88,101 | 0 | 0 |
| 合計 | 709,534 | 0 | 7 |
読めなかった 7 枚は、放送録画 7 本の各 1 枚である。どれも同じ理由で、録画がピクチャの途中から始まっていて、最初の 1 枚がピクチャとして完結していない。届いたまま書かれ、そう表示される。
MPEG-2 以外、4:2:2 と 4:4:4、MPEG-1、スケーラブルプロファイルは**推測せずに明示的に対象外とする。**対象外とした録画は原寸で書かれ、そう表示される。テストパターンのような合成映像は、ピクチャのバイトが係数ではなく位置とベクトルなので、何を指定しても 95% 程度にしかならない。指定に届かなかった実行は実際の値を表示する。
詳しくはディスク容量に合わせるにある。
データ放送を「運ぶ」と言っていたのに、運んでいなかった
BDAV ディスクを書くとき、書き出しの要約はデータ放送を運ぶと言っていた。**運んだことは一度も無い。**カルーセルは放送自身のテーブルを書き戻すパスが書くものだが、ディスクのストリームはそのパスを通らない。クリップの索引にも、プレイヤーにも、d ボタンの向こうのページを置く場所は無い。エンジンはずっと知っていて、メッセージだけが知らなかった。
いまは 3 か所とも同じ関数に聞く。トランスポートストリームであること、放送自身のテーブルを保つこと、そして Blu-ray 自身のストリームでないこと。ディスク・MP4・--tables muxer では、カルーセルは「運ばれるもの」ではなく「置いていかれるもの」の側に並ぶ。
そのほか
- ディスクの使用量の数字を GiB にした。ディスクを選ぶ欄は「BD-R / BD-RE 25GB」のままである。片方はパッケージに書かれている名前、もう片方はファイルマネージャーの表示と同じ 1024 換算の数字、という 2 つの別々の文である。
- 収まらなかったときのメッセージを 2 通りに分けた。**トランスコードを指示されていない実行が「映像をこれ以上小さくできませんでした」と言うのは嘘である。**試していない。いまはそちらには「トランスコードするを入れると収まることがあります」と言う。
- 英語版の複数形を 2 か所直した。出力設定の
1 cutsと、バッチのSleeping in 1 secondsである。日本語はこの数え方をしないので、どちらも日本語では間違っていなかった。 --fit bd30のような、覚え違いのディスク名に「それはサイズではない」と答えていた。bdで始まるものはディスクとして答え、実在する 4 枚を並べる。--helpの--fitの段落が、行継続の改行をそのまま抱えて 3 つの断片に割れていた。- 出力設定のディスク画面のスクリーンショット 2 枚を撮り直し、ガイドにゲージの単位のことと、読み込み中のキーフレームのカードのことを書き足した。
SmartCut v0.6.9
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.6.9 は 実際より遅く感じさせていたものを直した版である。報告は「Windows で出力終了後の挙動が遅い。BDAV では出力終了→索引作成→ISO 作成の間が非常に長い」だった。調べたら、いちばん長い区間は何も報告しないパスで、そのほかに 4 件出てきた。出力されるファイルの中身は 1 バイトも変わらない。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.6.9_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.6.9-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.6.9_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。4.1MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.6.9_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.6.9.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
出力が終わったあと、もう一度全部書いていた
.ts のカットは 2 回書かれる。 マルチプレクサが書き、そのあと放送の番組情報を入れ直すパスが、書き上がったファイルを全部読んで全部書き直す。挿入するので上書きでは済まない。これは .ts の既定であり、ブルーレイのクリップも部分 TS として同じ道を通る。このパスが今まで一言も報告していなかった。
700MB の放送録画をまるごとコピーして測った(キャッシュは温かい状態)。
| 所要 | |
|---|---|
--tables broadcast(既定) |
4.45 秒 |
--tables muxer(第 2 パス無し) |
3.16 秒 |
出力時間の 29% が、出力が終わったように見えたあとにあった。 ディスクが律速するマシンではもっと効く。書き込むバイト数が倍になるからである。ご指摘の「出力終了後」は主にこれだった。
いまは進捗がどちらのパスかを持ち、バーは 2 つを通して動く。前半 0.7 が書き込み、残りがテーブル。状況の行も変わる。
"cut_01.ts" を出力中: 映像を無劣化出力しています…
"cut_01.ts" を仕上げ中: 放送の番組情報を書き戻しています…
BDAV の「索引作成」も同じ形だった。到着時刻を書き直すパスが、その工程の入出力の 4 分の 3 を占めながら無言だった。ここも報告するようにした。
「どこまで進んだか」の言い方が、3 通りとも間違っていた
617MB のストリームを BDAV に書いたあとの内訳を測った。
| 読み | 書き | 報告 | |
|---|---|---|---|
| 到着時刻の書き直し | 1233MB | 617MB | 0 回 |
| エントリポイントの走査 | 623MB | — | 5 回 |
| ISO イメージ | 617MB | 617MB | 591 回 |
同じ 1 つのことについて、3 通りの間違え方をしていた。何も報告しない。5 回しか報告しない(パケットを数えていたが、ブルーレイのパケットはピクチャ 1 枚なので、2048 個に 1 回が 617MB で 5 回になった)。言い過ぎる(1MB ごと、20GB のディスクなら 2 万回)。
頻度の判断を各パスから取り上げ、前回から全体の 500 分の 1 動いたときだけ言うという 1 つの規則にした。上の 3 つはいま 500 回・70 回・295 回で、間隔も揃っている。1 本を通して、報告と報告の間がいちばん開いたところで 1.2% である。
出力画面が、同じ数字のために全部描き直していた
カットの進捗は書いたフレーム 16 枚ごとに出る。30 分の録画で 3,372 回、2 時間なら 13,500 回。そのたびに行の一覧をマークアップから作り直し、動いている行を見える位置に保つためにレイアウトを読み戻していた。毎秒 20 回である。
守りを 2 つ入れた。報告そのものを上の規則に通し、画面に出ている整数%と同じ報告では何も描かない。隣のディスクの工程がすでに持っていた守りである。
画像を、文字列で運んでいた
イベントは JSON なので、画像を送るにはまず base64 にしなければならない。実測(実素材の平均)。
| JPEG | 文字列にすると | 毎秒 | |
|---|---|---|---|
| 再生(ステージ 1280px・30fps) | 99KB | 132KB | 4.0 MB/s |
| フィルムストリップ 1 回(30 セル・200px) | 211KB | 281KB | ドラッグ中は毎秒 4 回まで |
再生はチャンネルで渡すことにした。大きな荷物はバイトのまま渡るので、符号化は不要で、運ぶ量は 4 分の 1 減り、デコードはブラウザ本来の経路になる。ストリップとステージの画像は、ウィンドウが取りに来られる場所へ移した。専用のスキームで、答えに入るのは 281KB の文字列ではなく 2KB ほどのアドレスだけである。
アドレスは画像の中身そのものにした。ドラッグとは同じリールを 1 セルずつずらすことなので、1 回の更新が要求する 30 セルのうち 28 セルは前回と同じ画像である。中身が同じならアドレスも同じなので、同じ画像を 2 つ持つことはなく、応答には「このアドレスの中身は変わらない」と書いてある。
25 秒・750 枚の再生で常駐メモリは 706MB → 716MB。録画を 80 回ドラッグしても 240,656KB → 240,480KB。どちらも増えていない。
キーフレームのサムネイルが、走査の間ずっと白かった
編集画面はコンテナ自身の答え、つまり長さ・画面サイズ・音声で開き、アクセスポイントを探す走査はその裏で走る。録画をまだ読んでいる最中でも開けるのはそのためで、ガイドにもそう書いてある。
ところがカードが欲しいのはマークの時刻ちょうどの画像で、それに答えるパスはウィンドウが開いている録画を読む。その録画を開けるのは走査である。走査が終わるまで要求は空で返り、カードは白いままだった。 1GB につき 1 秒、共有の上ならもっと長い。この録画が置いてあるのはたいてい共有である。
フィルムストリップには、その数秒分の答えがすでにあった。セルごとのコンテナシークで、時刻の近くに着地するものである。カードもこれを使うようにした。3.75GB の録画にマーク 9 個、編集画面を開くボタンを押した瞬間からの計測で 2.2 秒 → 1.5 秒。共有の上なら、差は走査の長さそのものになる。
仮の画像は描くだけでなく取っておく。走査が終わると一覧が描き直されるので、何か入っているカードが、正しいものが入るまでの途中で白へ戻ってはいけないからである。走査が終われば、カードが名乗っている時刻の画像に置き換わる。
ウィンドウのスレッドが、ファイルに触っていた
async でないコマンドは、ウィンドウを描いているスレッドで走る。人が選んだパスに触るものが 7 つあった。
目立つのはクリップ追加である。入力ごとに stat し、フォルダーなら中を歩き、ディスクなら索引を丸ごと読む。フォルダーを落とすと読み終わるまでウィンドウが固まり、眠っている共有に落とせば共有が起きるまで固まっていた。 この 7 つをスレッドの外へ出した。
そのほか
- テストは 23 スイート全部通っている。出力の中身を確かめるものも含めて、変わったものは 1 つも無い。
- 技術ドキュメントに経緯と計測を書いた。
SmartCut v0.6.8
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.6.8 は 入口のピクチャをマシンの全コアで復号するようにした版である。報告は 2 つ、「ファイル追加時の読み込みが遅い」と「MPEG2 以外でカット編集画面のフィルムストリップが付いてこない」だった。別々の不具合ではなく、原因は 1 つだった。レコーダーが焼いた BD-RE の 4K 録画 53 分は、追加してからピクチャが揃うまで 3 分 21 秒かかっていた。いまは 34.2 秒である。
あわせて 3 件直した。その読み込みがほかの作業を邪魔しないようにし、書き出しの計画が途中までしか見えていなかったのを直し、英語版の数え方を直した。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.6.8_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.6.8-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.6.8_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。4.0MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.6.8_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.6.8.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
1 枚ずつ復号していたので、コアが遊んでいた
録画を「入口のピクチャだけ」読むパスが 3 つある。一覧のサムネイル軌道、フィルムストリップ自身の復号、1 回読みの走査である。3 つとも、デコーダに 1 枚送り、汲み出し、フラッシュし、次を送るという形をしていた。
このフラッシュは手抜きではない。ストリームのパケットを間引いて渡されたデコーダは、出てくる順を決められない。並べ替えの基準はピクチャオーダーカウントで、連続していないピクチャどうしのカウントはどちらが先かを何も言わないからである。実測では、ブルーレイの入口のピクチャだけを渡したとき、ある h.264 デコーダは 1992 枚のうち 1814 枚しか返さず、その 1 割が順不同、1 枚は 8 秒早く出てきた。1 枚ごとに汲み出せば、出てくる順はファイルの順になる。
同時にこれが、16 コアのうち 15 コアを遊ばせていた。 libavcodec のスレッド化は 2 通りある。フレーム単位は複数のピクチャが同時に走っていることを前提にするので、フラッシュがそれを潰す。スライス単位は 1 枚が複数スライスに分かれていることを前提にする。ここで扱う素材でそれに当てはまるのは MPEG-2 だけである(マクロブロック行ごとに 1 スライス入っている)。
入口のピクチャ 400 枚を、デコーダのスレッド数 1 と 16 で復号してみた。
| 素材 | スレッド 1 | スレッド 16 |
|---|---|---|
| MPEG-2 1920×1080 | 毎秒 287 枚 | 毎秒 766 枚 |
| H.264 1440×1080 | 毎秒 105 枚 | 毎秒 122 枚 |
| HEVC 3840×2160 | 毎秒 35 枚 | 毎秒 34 枚 |
H.264 と HEVC は、16 コアを与えても 1 コアと同じだった。「MPEG2 以外で」という報告の内容は、全部これである。
フレームを分散させる
デマルチプレクサ 1 本が入口のピクチャのパケットを空いたワーカーへ渡し、ワーカーはそれぞれ自前のデコーダを持ち、返ってきたものはファイルの順に並べ直してから収集側に渡す。ワーカーが 1 枚に対してすることは、単一デコーダが毎枚していたことと同じである(送る、汲み出す、フラッシュする)。だから答えも同じである。
| 録画 1 本分(16 コア) | これまで | 0.6.8 |
|---|---|---|
| MPEG-2 1920×1080 放送 2 分 43 秒 | 0.64 秒 | 0.26 秒 |
| VC-1 1920×1080 BD 1 分 2 秒 | 0.72 秒 | 0.17 秒 |
| H.264 1440×1080 レコーダー BD-RE 46 分 | 43.9 秒 | 5.5 秒 |
| HEVC 3840×2160 レコーダー BD-RE 53 分 | 200.8 秒 | 34.2 秒 |
4 コアの開発 VM でも、30 分の放送録画が 8.2 秒から 4.6 秒になる。
フレームから何を作るかも、フレームと一緒に分散させた。4K を 192 ピクセルに縮めるのも JPEG にするのもワーカー側で済ませるので、スレッドをまたぐのはフレームではなくサムネイルになる。前のフレームとの比較と間引きだけは、順番が決まっていないとできないので 1 本のスレッドに残した。
プールの幅はコア数ではなくメモリの予算で決める。 ワーカーはすぐフラッシュしてもデコーダの中に数枚を抱える。4K 10bit は 1 枚 25MB なので、16 ワーカーでは常駐 1.4GB になった(単一デコーダは 0.4GB)。そこで、保持するフレームの合計 768MB を配ることにした。4K は 7 ワーカー、それ以外はマシンのコア数になる。損はほとんど無い。効きは 16 まで行く前に頭打ちで、8 ワーカーで毎秒 161 枚、16 ワーカーで 174 枚である。
フィルムストリップが付いてこない
苦情のもう半分はここである。軌道ができるまでの間、ストリップには答える材料が無く、描くセルを全部その場で録画から復号する。4K では 1 枚 28 ミリ秒なので、11 セルで 0.4 秒。プレイヘッドはとっくに先へ行っている。
ストリップの復号も同じように分散させた。4K 素材の GOP・6 秒で、手持ちゼロの状態の 1 回の再描画(11 セル)は 482 ミリ秒から 196 ミリ秒になった。そして軌道そのものが 6 倍速く完成するので、「材料が無い時間」自体が短くなる。
広い設定(GOP・3 分など)では、セルごとに別の続きになるのでプールは何も買わない。1 枚を復号するためにデコーダを 16 個開けば、復号そのものより高くつくので、プールは最初の続きが持っているフレームの数より広くは開かないようにした。入れる前より遅くなる設定は無い。
ついでに、ずっと間違っていた画像が見つかった
新旧の結果を 1 枚ずつ突き合わせるツール(examples/poolcheck.rs)を書いて、素材 6 本で比べた。時刻も、画像も、シーンの一覧も、全部一致した。
1 つだけ食い違ったのが、放送 MPEG-2 の 314 枚のうち 3 枚である。3 枚とも冒頭 20 秒の中にあり、間違っていたのは古いほうだった。走らせるたびに違う画像を返し、そのうち 1 枚は縦縞に割れていた。16 本のフレームスレッドを毎枚フラッシュする使い方は、結果が一定になる保証のあるものではない。録画の頭、最初の GOP が半分しか無いところでは、実際に一定ではなかった。いまは毎回同じ画像が出る。
全コアを使うのはいいが、マシンを占領してはいけない
入口のピクチャは全コアで復号されるようになった。追加は速くなった。ただしマシンは SmartCut のものではない。裏で 1 本読み込んでいる間、ほかのソフトからコアが消える。しかも裏の読み込みは、ここで唯一だれも見て待っていないものである。
そこで、読み込みのパスは nice 10 で走るようにした。 4 コアの開発 VM で、競合する仕事を 4 スレッド走らせながら 2.6GB の放送録画を読ませて測った。
| ほかの仕事 | 読み込み | |
|---|---|---|
| それぞれ単独 | 11.9 秒 | 30.3 秒 |
| 同時・これまで | 16.3 秒 | 30.3 秒 |
| 同時・0.6.8 | 12.5 秒 | 88.8 秒 |
ほかの仕事は 1.4 倍かかっていたのが、単独時の 5% 増まで戻る。代わりに読み込みが遅くなる。ただし遅くなるのはほかがコアを欲しがっている間だけである。マシンが空いていれば違いは無い。画像のパスは 3.79 秒と 3.83 秒で、どちらも同じだった。nice 5 も測ったが、ほかの仕事が 15.6 秒までしか戻らず、採る価値が無かった。
下がるのは一覧の読み込み、ファイルを開いたときのプロキシとサムネイル、CM 検出である。フィルムストリップと出力は下げない。 ストリップはポインタに数フレームで答えるために在るもので、出力は人が待っているものそのものだからである。
Linux では優先度がスレッドに付き、そのスレッドが起こすスレッドへ受け継がれるので、libavcodec のスレッドまで一度に届く。Windows は継承しないので、SmartCutが作るスレッドが各自で申告する。
書き出しの計画が、途中までしか見えていなかった
カット編集画面の下に出る内訳は、3 行分の高さで固定してある。上の画面が計画の増減で上下しないためで、ふつうのカット 1 回は コピー・再エンコード・コピー の 3 行に収まる。
カット 2 回は 5 行になる。 継ぎ目ごとに再エンコードとコピーが付くからである。そして CM を 2 箇所落とすというのは、SmartCutがいちばんよくやる仕事である。枠はスクロールするので中身は失われていない。だがデスクトップのスクロールバーは触っている間しか出ない。5 行のうち 3 行が、計画の全部に見えていた。
自分のドキュメントにも出ていた。ユーザーズガイドの「再エンコードが必要になるとき」の図は 4 行の計画を写したもので、2 つ目の区間のコピー、つまりその区間の 9 割が、写っていなかった。
いまは下に続きがあるとき、右端に細いバーが出て、いちばん下の行が影に沈む。3 行ちょうどのときは何も出さない。全部見えているのに「まだ下がある」と言うことになるからである。
英語版が「1 cuts」と書いていた
計画の行は、英語版では 1 ranges, 0 cuts と出ていた。英語のカタログができてからずっとである。ほかにも 1 blocks、1 keyframes、1 frames re-encoded、Remove all 1 jobs from the queue? など、20 箇所ほど同じだった。
日本語はこの数え方をしない。毎日日本語で見ているから、ずっと残っていた。
カタログの {n} は数そのもの、{n?s} は数が次の語に与える変化、ということにした。{cuts} cut{cuts?s} は 1 なら "1 cut"、2 なら "2 cuts" になる。英語の行に書くのは、これが英語の都合であって、日本語の行には不要だからである。
ディスク選択画面の clip(s) と track(s) はそのままにした。あれは意図してそう書いてあり、間違ってはいない。
英語版のスクリーンショット 6 枚を撮り直した。日本語版は、もともと間違っていないので変わらない。
そのほか
SmartCut v0.6.7
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.6.7 は GUI の日本語を書き直した版である。この GUI は日本語で書かれているのに、文言のかなりの部分が英語から戻ってきたもので、英語のまま読めた。カタログ 50 行を直した。きっかけになった 1 行は、データ放送を「青いボタンの向こう」と説明していたことである。青は 4 つのカラーボタンの 1 つで、データ放送を開くのは d ボタンである。
同時に、カット編集の再生を 3 か所直した。番組の変わり目で音が止まる。プレビューが録画のフレームレートで出ない。ウィンドウを閉じても音が鳴り続ける(Windows から「どこからか音楽が流れる」として報告された)。そして、レコーダーが焼いた BD-RE の 20 本目がようやく切り出せるようになった。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.6.7_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.6.7-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.6.7_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。3.9MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.6.7_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.6.7.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
日本語で書かれているのに、日本語で読めなかった
この GUI の文言は日本語が正本で、英語はそこから訳したものである。ところが実際には、英語で書いた説明が日本語に戻ってきた行がかなりあり、語順も語の選び方も英語のままだった。意味は通るが、日本語として誰も言わない言い方になっている。
いちばんはっきりしていたのが「青いボタン」である。データ放送のチェックボックスの説明が「青いボタンの先にあるページ」と言っていた。青は赤・緑・黄と並ぶカラーボタンで、番組の側が使う。データ放送を開くのは d ボタンである。同じ誤りが英語側にも、ガイドにも、ソースのコメント 2 か所にもあったので、全部 d に直した。
ほかにも:
- 字幕の行き先が
カットの傍らに (.idx / .sub)だった。ファイルの置き場所を「傍ら」と言う人はいない。別ファイルに出力にした。カットの中に入れるほうは出力ファイルに含めるである。 - ディスクが持っている索引を
ディスクの索引、シーク用のものを索引と呼んでいた。別のものが 1 つの語を分け合っていたうえ、どちらもレコーダーが使う語ではない。ディスク側はディスクの管理情報、シーク用はインデックスに統一した。 持ち出せません→出力できません。環境設定で答えます→環境設定で決めます。サムネイルは作成できず→サムネイルを作成できませんでした。動詞で終わるべき文が名詞で終わっていたものが 6 つあった。- プレビューのフレームを
絵と呼んでいた箇所をフレームにした。
ガイドは GUI を引用している箇所が追随し、用語の変更は技術ページにも通した。日本語のスクリーンショットは 12 枚を撮り直している。
番組の変わり目で音が止まる
**録画の冒頭は、その番組のものではない。**チューナーは早めに録り始めるので、ファイルの頭には前の番組の終わりが入る。そこだけ音の形が違うことがある。ステレオの番組の前に、モノラルのニュースが読まれている。珍しい録画ではない。
プレビューの音は swresample のコンテキストを 1 つ通る。これは最初に復号したフレームの形式・チャンネル配置・レートで作られる。swresample は、作られたときと違う形のフレームを受け取らない。番組の変わり目で Input changed を返し、そのエラーが再生スレッドを終わらせる。フレームは流れたまま、音だけが番組の始まった瞬間に消える。
冒頭 3.243 秒がモノラルの 50 分の録画で測ると、変換できたのは 151 フレームで、そのあとは 1 枚も通っていない。いまは届いたフレームごとに形を訊き、前と違えばコンテキストを作り直す。同じ録画で 937 フレーム全部が通る。変わり目で 1 回確保するだけである。
書き出し側の同じ問題は 0.6.6 で直してある(settled_shape)。残っていたのは鳴らす側だった。
プレビューは録画のフレームレートで出る
これまでは毎秒 15 枚(プロキシからなら 24 枚)しか要求していなかった。期限を過ぎたフレームを捨てる仕組みが無かったからである。間に合わないパソコンでは、フレームを減らすのではなく再生全体が遅れる。音はサウンドカードの時計で進んで誰も待たないので、遅れたフレームはそのまま音とのずれになる。
いまは、自分の時刻を 2 フレーム以上過ぎたフレームは出さずに捨てる。捨てても払うのは復号だけで、JPEG もデータ URL も作らない。だから録画そのもののレートを要求してよくなった。そのパソコンが描ける枚数だけを、時刻どおりに出す。4 コアのマシンで 1440x1080 の MPEG-2 を直接復号して、毎秒 30.5 枚を実測している。
ウィンドウを閉じても音が鳴り続ける
Windows から「どこからか音楽が流れる」という報告があった。カット編集のウィンドウを閉じたときである。
再生は 2 つのスレッドで動いていて、どちらも Playing というフラグ 1 つしか見ていない。ウィンドウそのものは持っていない。そして、ウィンドウが閉じてもそのフラグを下ろす者がいなかった。フレームは行き先が無いだけだが、音のスレッドはサウンドカードに合わせて進むので、録画の残り分だけ鳴り続ける。番組の頭で閉じれば 45 分である。
ウィンドウの CloseRequested と Destroyed で下ろすようにした。修正前はウィンドウが消えたあとも CPU を 3 秒あたり 83〜85 tick 使い続け、修正後は 0 である。
エントリーポイントマップが、別の何かを指している
レコーダーが焼いた BD-RE 4 枚・20 本のうち、19 本は切り出せて 1 本だけが止まっていた。継ぎ目の問題ではなく、エントリーの問題だった。
1 本のクリップは 6 つの区間(ATC シーケンス)でできている。そのうち 4 番目だけが、指している位置のピクチャより 6.000 秒早い時刻を書いていた。先頭 2 点はさらに 11.651 秒早い。これは細かいエントリが持つ 11 ビットの一周分である。区間の長さも同じだけ狂っていて、ピクチャ 289 秒分に対して 316 秒と書いてある。カットから見えていたのは「エントリーポイントに出会わないまま通り過ぎた」というエラーだった。マップの言う時刻へシークし、読み進め、約束されたピクチャは 8 秒先にあった。同じクリップの他の 5 区間も、同じディスクの他の 7 クリップの 3,592〜3,615 点も、ストリームと 1/1000 秒で合っている。
どの区間が信用できるかはマップのどこにも書いていない。そこで全部に 1 つずつ訊くことにした。シーク 1 回と短い読み取り 1 回で済む問いである。あなたの先頭のバイトにある最初のピクチャは、先頭のエントリが指しているピクチャか。 違えばその区間のエントリだけ捨て、ストリームを読んで作り直す。読むのはその区間だけで、クリップ全体ではない。そして手前の継ぎ目を、その区間が実際に持っている最後のピクチャまで引き戻す。
訊くのは継ぎ目を持つクリップ、つまりレコーダーが焼いたクリップだけであり、ストリームから作っていない索引に対してだけである。走査して作った索引は、自分が読んだものと食い違えない。20 本のうち発動するのは 1 本の 1 区間だけで、残り 19 本の計画はコピー秒数まで以前と同じである。直った 1 本はコピー 99.8% で書き出せる。隣のタイトルと同じ値である。
SmartCut v0.6.6
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.6.6 は データ放送を持ち出せるようにした版。青いボタンの向こうにあるものである。カットが唯一運べずにいたストリームで、コーパスから無作為に 40 本見たところ 30 本が積んでいた。もう 1 つ、音声のチャンネル数とサンプリングレートを録画の冒頭から読むのをやめた。**ステレオの番組がモノラルとして書き出されることがあった。**出力中の知らせがどの画面にも出ていなかったのも直した。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.6.6_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.6.6-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.6.6_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。3.9MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.6.6_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.6.6.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
データ放送は多重化を通り抜けられない
放送が送っているのは映像と音と字幕だけではない。地域の天気、番組自身のページ、道路の状況。送り方はカルーセルで、番組が続くあいだモジュールの一式を繰り返し送る。途中から受信した機器でも数秒で全部そろう、という仕組みである。占有率は局によって幅がある。タイトル画面だけを送る局で 0.9%、地デジ各局で 10〜14%、ページ数の多い BS の局で 22% だった。
これは多重化を通り抜けられない。カルーセルは PES ではなくセクションで送られ、libavformat の demuxer は自分が読むテーブル以外のセクションを渡さない。ストリームの一覧には出る(Unknown: none ([13][0][0][0] / 0x000D))が、中身は一切出てこない。-copy_unknown を付けてコピーさせても、ffmpeg は自分のマップにエントリだけ書き、その後ろにパケットを 1 つも書かない。データ放送を名乗っていて持っていないファイルができる。
そこで、パケットを録画からバイトとして取り出し、書き上がったファイルにバイトとして入れる。やるのは、すでに表を書き戻しているパスである。そのパスはカットを 1 パケットずつ読み、それぞれが何秒の位置かを知っている。だから録画を横で読み、送られていた位置へ配り直せばよい。セクションは時刻を持たないので、継ぎ合わせるものは何も無い。置いて、連続性カウンタを振り直すだけで、あとは届いたままである。
**カットしたカルーセルは壊れたカルーセルではない。短いカルーセルである。**一周は 3〜6.5 秒なので、通常の長さの区間なら一周分が丸ごと入る。カット点がするのはモジュールの途中での中断で、ブロックを取り逃した受信機は次の周回を待つ。受信が切れたときに現にやっていることである。
置けるのは、放送自身の表を持つ素の .ts だけである。カルーセルを書くのは表のパスなので、--tables muxer には書く場所が無い。Blu-ray の形式には置き場が無く、MP4 はそもそも TS ではない。捨てるなら --no-data-broadcast、GUI なら環境設定の「出力設定」にある同じチェックを外す。断って得られるのはサイズである。
冒頭のフレームは、その番組のものではない
libavformat は、ファイルの先頭から数メガバイトの範囲で最初に見つけたフレームを見てトラックを説明する。放送の録画では、そのフレームが番組のものではないことがよくある。チューナーは早めに録り始めるので、ファイルの頭には前の番組の終わりが入る。そこだけチャンネル数が違うこともある。ステレオの番組の前に、モノラルのニュースが読まれている。珍しい録画ではない。
それが 3 秒あるだけで、50 分のステレオのトラックがモノラルと呼ばれていた。以降の処理はすべてその説明に従う。継ぎ目のフレームを書くエンコーダが 1 チャンネルで開く。その前に付く ADTS ヘッダにも 1 チャンネルと書く。**TS のデコーダが読むのはこのヘッダである。**トラック全体の再エンコードでは、番組の 2 チャンネルが最初から最後まで 1 つに畳まれる。カットから書いた BDAV のクリップ索引も、そのトラックをモノラルと記録する。
そこでフレームをもう一度見る。録画の中の 4 か所へシークし、それぞれで 1 フレームだけデコードし、過半数が一致したチャンネル数とサンプリングレートを採る。5.8GB の録画で 10 ミリ秒ほどである。シーク 4 回とフレーム 4 枚しか必要としない。
**ビットレートも同じフレームから読んでいる。**理由が同じなので、やはり間違っている。5.1 の番組の前にステレオの冒頭が付いていると、386 kbit/s で運ばれているトラックをコンテナは 208 kbit/s と申告する。そのまま全体を再エンコードすれば、6 チャンネルにステレオ番組のレートを使うことになる。そこで冒頭の説明の残りと一緒に捨て、コーデックとチャンネル数から決まる標準的な値を代わりに使う。5.1 の AAC なら 384 kbit/s で、録画自身が運ばれていたレートである。
最初の答えではなく過半数を採るので、本当にモノラルの録画はモノラルのまま出る。どの地点もプローブと一致するため、何も直さない。**番組が複数入った録画にも手を出さない。**見た地点どうしが一致せず、その録画に固有のチャンネル数というものが無いからである。検査するのは放送から録ったものだけで、ディスクのクリップは対象外である。最初のフレームから 1 番組なので、冒頭と食い違いようがない。
出力中の知らせが、出力画面に出ていなかった
出力が知らせることは 1 本の行に書いていた。その行は入力設定の画面にある。出力は出力画面から始めて出力画面で見るものなので、**どれ 1 つとして目に入らなかった。**フォルダーに枝番が付いたこと。ディスクの索引が書けなかったこと。イメージが作れなかったこと。イメージができたのでフォルダーを片付けたこと。
出力が始まらなかったときはさらに悪い。理由を知らせてから出力設定の画面へ送り返すが、その画面にも行が無い。移った先にあるのはフォーカスの当たった入力欄だけで、何がいけないのかはどこにも書かれていない。**バッチ出力ツールに至っては、入力設定の画面を一度も描かない。**開けなかったジョブも、すでにキューにある旨も、途中で落ちたジョブも、あのウィンドウには何も出ていなかった。
出力画面に専用の行を設けた。出力が終わっても消えない。隣の要約と同じ扱いである。出力設定にはタブの隣、バッチ出力にはバーの空いていた右半分に置いた。読み込み・サムネイル・CM 検出の進み具合は入力設定に残した。あれは一覧についての知らせで、一覧はあの画面だからである。
書き終えた直後に、表示先のフォルダー名が次回の枝番に変わるのもやめた。night に書き終わった瞬間に night-2 と表示されていた。書いた場所とは別のどこかへ出力されたように読める。
検証
- 単体テスト 260 件、E2E スイート 23 本が全部通る(VC-1 の 1 本は素材が必要なので別)。
- 放送録画 40 本を無作為抽出して
--analyzeまで通し、SmartCut 由来のエラーは 0 件。 - データ放送は、地デジと BS の実録画 3 本で全モジュールが録画自身のバイトと一致し、連続性カウンタにも飛びが無い。素の
.tsでも部分 TS でも結果は同じである。 - 音声は、冒頭 3 秒がモノラルの 5.8GB の実録画で確かめた。2 区間カットの ADTS ヘッダ 5,676 枚がすべて 2 チャンネルと書かれ、うち 5,672 枚は録画自身のバイトのままである。
- 新しいスイート
tests/run_audio_head_tests.shの 12 件は、修正前のバイナリでは 7 件落ちる。 - GUI は実機の画面で起動し、出力・出力設定・バッチ出力の 3 画面に知らせが出ることを確かめた。
技術的な詳細は docs/technical/broadcast-ts.ja.md と docs/technical/audio.ja.md に書いた。
SmartCut v0.6.5
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.6.5 は 切ったファイルの番組情報が、プレーヤーからまた読めるようになった版。0.3.1 以降、.ts は部分 TS として書いていた。規格の言葉でいえば録画とはそれのことだが、**日本の録画まわりのソフトはどれもそれを読まない。**TvtPlay で再生しても、TVTest には番組名も放送局名も時刻も出ていなかった。.ts は放送自身の SDT・EIT・TOT を書き戻すようにした。.m2ts は今までどおり部分 TS である。Blu-ray のクリップとはそれのことだからである。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.6.5_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.6.5-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.6.5_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。3.9MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.6.5_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.6.5.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
誰も読まない場所に書いていた
放送は自分自身についても語っている。どのサービスか、放送局の名前は何か、いま何を放送していて次は何か、いまは何時か。SDT・EIT・TOT がそれである。カットにもそれを持ち出していた。持ち出してはいたが、置き場所が違った。
部分 TS は、そういうテーブルを 1 枚も持たない。代わりに SIT が 1 枚あり、同じ事実がすべてそこに入る。DVB も ARIB もそう決めていて、Blu-ray レコーダーが書くのもこれである。0.3.1 で既定にしたのはそのためだった。
ところが **SIT を読むものが無い。**TVTest も EDCB も ffmpeg も、読むのは SDT と EIT である。部分 TS に ffprobe をかけてもサービス名は返ってこない。TVTest が見にいく PID は空だったので、TvtPlay で開いた録画には番組名も放送局名も時刻も出なかった。規格の答えとしては正しく、実際には誰も読めないファイルだった。トラック一覧のほうは「番組情報は .ts に書き出すときそのまま引き継ぎます」と表示していたので、なおさら始末が悪い。
どちらで書くかは拡張子が決める
書いているものが何かによって、正しい答えが変わる。
.m2ts は Blu-ray のクリップである。そこでの部分 TS は好みではなく形式そのものなので、--bdav でディスクに載せる場合も単体で書く場合も部分 TS になる。フレーミングを選ぶ判定と同じ判定である。
それ以外は人が開くファイルなので、放送自身のテーブルのまま書く。PMT を作り直し、SDT を録画自身のものに置き換え、EIT の present/following と TOT を本来の PID に戻す。バイト列は録画のものなので、番組名も放送局名も ARIB の文字符号のまま運ばれる。
--tables partial|broadcast|muxer はどちらの向きにも上書きできる。--tables partial が今までの既定である。
**どちらの形も新しくはない。**両方とももとから実装され、両方ともテストされていた。変わったのはどちらを選ぶかだけである。32 局の録画から 1 本ずつ取って確かめた。
字幕トラックの並びと名前
放送は字幕と文字スーパーを、そのときどきの順で PMT に並べる。同じ順とはかぎらない。手元の 25 本のうち 6 本は文字スーパーが先だった。一覧はその順に従っていたので、録画ごとに並びが入れ替わっていた。
**種類で並べるようにした。**字幕、文字スーパー、ディスクが描くもの、の順である。同じ種類の中では録画の順のままで、これが 2 か国語を見分ける手がかりになる。行には番号を振り、番号は名前の前に置いた。後ろに置くと本数の勘定に見える。字幕 1 と 文字スーパー 2 が並ぶと、1 本目の字幕と 2 本目の文字スーパーに読めてしまう。選ぶものが 1 つしかない録画には番号を出さない。
一覧の呼び名も直した。これまで「文字」と呼んでいたものは「字幕」である。英語も text から subtitles にした。
SmartCut v0.6.4
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.6.4 は 4K 放送を録ったディスクを、端から端まで通せるようにした版。松下機が BS4K を焼いた BD-RE を初めて通し、4 か所で止まった。番組名は化け、冒頭は 13 秒も再エンコードし、音声はスマートレンダリングされず、字幕は丸ごと置いていかれていた。**4 件とも直した。**ついでに、切るものが 1 つも残らないカットが中身のないファイルを「書きました」と報告していたのと、時刻の表示が 1/100 秒足りないことがあったのも直した。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.6.4_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.6.4-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.6.4_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。3.9MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.6.4_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.6.4.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
4K レコーダーの書く名前は UTF-8 である
これまで読んできたレコーダーもオーサリングツールも、プレイリストには放送そのものの符号化を書いていた。**4K レコーダーは UTF-8 を書く。**放送が独自の文字として送る記号も、あらかじめ Unicode のものに直して入っている。ARIB として読むと、ディスクが NHK BS と呼んでいるチャンネルは意味を成さない仮名 15 文字になり、そのディスクの行は 1 つ残らず出鱈目な名前で並ぶ。
どちらであるかは、ファイルが名乗るバージョンで分かる。4K 録画のプレイリストとクリップ索引は 2.00 で、オーサリングツールは 1.00、HD レコーダーは 1.10 である。ただしそれだけでは足りない。**2.00 のディスクでも info.bdav は 1.00 のままである。**そこでバイト列も見るが、見て分かることには限りがある。ARIB は文字集合の切り替えに UTF-8 では現れないバイトを使うけれども、**漢字だけで書かれた名前は切り替えを一度も使わない。**復号の出発点が漢字だからである。そういう名前は UTF-8 としても妥当で、読み方を間違えても別の何かとして通ってしまう。だから 2.00 は UTF-8 として読み、それ以外は ARIB では書きようのない文字がバイト列にあるときだけ UTF-8 とする。
番組内容も同じところで直した。UTF-8 の改行 0A を ARIB の切り替えと読み違えていたので、名前を直したあとも内容だけが出鱈目のままだった。
一覧に出す音声の名前も、ここで正確にした。ストリーム種別 0x0F は ADTS フレームの MPEG-2 AAC、0x11 は LATM フレームの MPEG-4 AAC である。一覧はその違いを書き分けられる。そして 4K レコーダーは標本周波数に 15 を書く。索引が名乗れるレートのどれでもないので、**推測せず、何も書かない。**レートはフレーム自身が持っているので、録画を開けばトラックの行に 48 kHz と出る。
冒頭の 13 秒を再エンコードしていた
カットはエントリーポイントからコピーを始める。先行ピクチャを捨てられないエントリーポイントは、コピーを始めてよい点ではない。そこより先に表示されるピクチャが、1 つ前のグループを参照しているからである。参照先はカットの向こう側にある。どの点がそれに当たるかは、ピクチャを 1 枚ずつ見て決めていた。H.264 のエンコーダは、先行ピクチャ自身を参照ピクチャにするピラミッドを組んでよいからである。
**HEVC はそれを規格の側で答えている。**HEVC の先行ピクチャは RADL と RASL で、どちらも同じエントリーポイントの後続ピクチャから参照されてはならない。だから常に捨ててよい。RASL に至っては、そこから再生を始めたデコーダは捨てることを求められている。
裏返して言うと、カットは 4K 放送で二重に間違えていた。**4K 放送のランダムアクセス点は全部 CRA で、IDR が 1 枚も無い。**計測した点は全部「始められない」と読まれ、計画は計測した範囲の外、境界の前後 24 点の向こうにある最初の点まで飛んで、そこまでを全部再エンコードしていた。4K レコーダーのディスクから 1 分を切り出すと、冒頭の 13.252 秒が再エンコードされていた。
いまは 0.444 秒である。境界が落ちた 0.534 秒のグループそのもので、範囲に対して 22.8% が 1.4% になった。新旧の出力を 1 フレームずつ突き合わせて、平均 62.7 dB・最悪 52.4 dB、順番の狂ったピクチャは 1 枚も無く、範囲は復号エラーなしで通る。
シーク用索引はこのためにバージョン 5 にした。**保存された索引には、どのコーデックのために作られたかがどこにも書いていない。**見つかればそのまま信じるので、これより前に索引を作った 4K 録画は、何度開いても 13 秒待ち続けることになる。
4K の音声がスマートレンダリングされなかった
4K 放送が運ぶ AAC は HD 放送のものと同じで、規格が許すもう一方のフレーミングになっている。LOAS/LATM フレームの MPEG-4 AAC LC で、ストリームの構成を固定ヘッダではなくビットで名乗る。ストリーム種別は、ADTS の AAC が 0x0F であるのに対して 0x11 である。このフレーミングのせいで 2 つのことが起き、そのトラックのスマートレンダリングは終わっていた。どちらもコーデックではなくフレーミングの話である。
**aac_latm という名前のエンコーダは無い。**LATM はフレーミングでありコーデックではないからである。libav に問い合わせても見つからないので、カットはその旨を注記して境目のフレームを丸ごとコピーしていた。1 回のカットにつき注記が 2 つ、すべての 4K 録画で。そのフレームを書くのは素の AAC エンコーダである。
**そして LATM のフレーミングはこちらで書かなければならない。**ADTS ヘッダを既にそうしていたのと同じ理由による。エンコーダが返すのは生のフレームで、パケットになったものにマルチプレクサは手を触れず、同期語の付いていないペイロードを継いだところでそれはフレームではない。
latm.rs はレコーダーが使う形だけを書く。プログラム 1 つ、レイヤー 1 つ、1024 サンプルの AAC LC、構成は毎フレーム書き直す。書く前に録画自身のフレームを読んで、その形であることを確かめる。レートを完全な形で書いているものや、チャンネルの並びをフレームの中で説明しているものは断って、これまで通りコピーする。
文字スーパーと 4K の字幕を置いていっていた
放送が送る文字は字幕だけではない。その隣を文字スーパーが流れている。地震、開票、行方不明者。放送中の画面に局が書き重ねるあの行で、専用のストリームで届く。そして **4K 放送の字幕はまったく別の形式である。**TTML、字幕 1 枚につき XML 文書 1 つ。どちらも捨てられていて、4K 録画のカットはそれを 1 行で告げていた。しかもその 1 行は前半も後半も間違っていた。「持ち出せません: 文字スーパー」。
**libav は 3 つのうち 1 つだけに名前を付け、残り 2 つを一緒くたにする。**HD 放送の字幕は arib_caption として返る。その文字スーパーと 4K 録画の字幕は、どちらも bin_data、種別を名乗らないバイト列として返る。
見分けるのは録画自身の map である。ARIB はストリームを 1 バイトのコンポーネントタグで呼ぶ。0x30〜0x37 が字幕、0x38〜0x3F が文字スーパー。その隣にあるデータ符号化方式記述子が、そもそもその文字が ARIB のものかどうかを示す。**4K 録画はその記述子もその文字も持たない。**map は開くたびに読むようにした。map が読めなかったところでは libav 自身の名前を代わりに使う。ディスクのクリップや、字幕ストリームを 1 分遅れて足す局に、それで対応できる。
3 つとも .ts に運ぶようになり、3 つとも画面に出せるようになった。文字スーパーを読むのは字幕と同じコードである。同じ文字が同じ形で来るので、違うのはペイロードの先頭に立つ識別子だけである。**ただしトラックは分けてある。**文字スーパーは番組ではなくその時間帯に属するものなので、台詞を探している人の前に地震速報が混ざらないようにした。
4K の字幕は、振り分けるだけでなく読む必要があった。ほかのどのストリームとも違うことが 2 つある。
**時計があるべきところにカウンタが入っている。**レコーダーはパケットに 1、2、3 と打つ。言葉が出ている時刻は文書の中に、文字として書いてある。
**その時刻の原点はクリップの提示開始である。**ファイルの先頭ではない。どこがそれかはディスクの索引に書いてある。プレイリストの IN_time が運んでいる数である。提示開始が 0.5 秒違う 2 本のクリップで、最初の字幕がどちらもその 5.000 秒後、タイトルバックに切り替わるフレームに乗ることを確かめた。ファイル自身の先頭から数えると、この 2 本は 1.2 秒と 1.7 秒ずれる。
だからカットは文書の中の時刻を書き換えて書き戻す。文書の長さは変えない。HH:MM:SS.mmm は固定幅で、レコーダーが文書の前に置く 12 バイトが文書長を数えているからである。どの区間にも入らない字幕は運ばない。区間の頭をまたぐ字幕はその頭から始め、区間の末尾を越える字幕はそこで終わる。実際のディスクの 2 区間カットを読み返すと、11 枚が 2 つの区間の中に収まり、先頭は 0.000 に、末尾は区間の終わりに切られていた。
すべてカットしたら、中身のないファイルを「書きました」と言っていた
smartcut 録画.ts --cut 0-9999 -o out.ts は plan : 0 range(s), -0.000s output と表示し、最後まで走り、0 バイトのファイルについて wrote out.ts と報告していた。編集画面でクリップを丸ごと切っても同じ結果になる。しかも出力画面はそのあいだ「なし。全編を無劣化コピーします」と表示していた。再エンコードする区間が無いことと、区間そのものが無いことを取り違えていた。
範囲が逆順のときは前から断っていて、その注記に理由が書いてある。区間を 1 つも選ばない指定は短いカットではなく間違いであり、以前は中身のないファイルを書いたと報告するところまで運ばれていた。同じ間違いが、範囲を与える道ではなく、範囲を計算する道から入ってきていた。
断るのはエンジンにした。出力ファイルを作る前である。どの呼び出し側もそこを通る。コマンドラインはその手前で、録画の長さを添えて言う。ウィンドウは、最後のカットが最後の区間を閉じたときに編集画面が使う言葉と同じ言葉で言う。書き出すように見える動きをしてから最後に断る、という順序にはしない。
時刻が 1/100 秒足りないことがあった
時刻の表示は切り捨てで正しい。タイムコードはフレーム番号と同じく「その 1/100 秒に入った」ことを表すものである。間違っていたのは、フィールドごとに切り捨てていたことである。
CM 検出が 60.06 秒と 30.03 秒の 2 ブロックを見つけたとき、一覧は合計を 00:01:30.08 と書いた。エンジンは同じ 2 つを 90.090 秒と呼んでいた。数え損ねてはいない。60.06 と 30.03 は、どの計算機にもある 2 進の算術では 90.08999999999999 になる。(t % 1) * 100 はそこで 9 ではなく 8.9999… になる。同じ切り捨てで 3599.99 は 00:59:59.98 になり、負の時刻は 1/100 秒だけ逆方向にずれていた。
いまはウィンドウが 1/100 秒、コマンドラインがミリ秒の整数を 1 つだけ作り、すべてのフィールドをそこから読む。切る前に 100 万分の 1 秒を足す。1/100 秒よりはるかに小さく、数回の足し算が落とすものよりはるかに大きい。
コマンドラインには同じ過ちの裏側があった。**秒だけが四捨五入され、時と分は切り捨てられていた。**だから 1 分をわずかに切る時刻は 00:00:60.000 と出た。どの時計にもない読みである。テストで押さえた。
英語表示で、文字スーパーが別の名前で呼ばれていた
用語のカタログは tracks.superimpose を 2 回持っていた。1 度はトラックの種別名として、tracks.audio や tracks.graphics の隣に。もう 1 度は「持ち出せません: …」を締める語として。**オブジェクトリテラルのキーの重複はエラーにならず、後ろが優先される。**だから英語のトラック一覧は Crawl と言うべきところで superimposed text と言い、前者の定義には一度も届いていなかった。
日本語では見えない。どちらも「文字スーパー」で、2 つの行はどちらの読み方でも同じに見える。だから残っていた。
後ろのほうを tracks.gone.superimpose にした。1 つの種別に 2 つの名前があるのは意図したことで、一覧はトラックを「それが何か」で呼び、置いていく旨の文はまた別の言い方を必要とする。ただしキーは分ける。
--help が答えられていなかった
smartcut --help は unknown option --help と言って失敗で終わっていた。使い方の文はずっとあった。録画を 1 つも指定せずに走らせたときに出るのがそれである。ただし**それを指定する方法が無かった。**いまは --help と -h が標準出力にそれを出して正常に終わる。両方の経路が同じ文を読む。文の最後で docs/user-guide/cli.md を指している。全オプションはそこにある。
そして 1 つの文が、SmartCutに無いフラグを名乗っていた。ディスクイメージの中の録画にプロキシを指定すると --make-proxy ... needs -o と断られる。フラグは --proxy である。
そのほか
- **ドキュメントが現状と食い違っていた。**README と GUI ガイドは「文字スーパーとデータ放送はカット後のタイムラインに載せられない」と書いたままだった。文字スーパーは運ぶようになり、持ち出せないのはデータ放送だけである。制限の一覧は
.tsが運ぶ字幕を 2 種類と数えていた。4 種類ある。ARIB 字幕、文字スーパー、4K の TTML、ディスクが描く PGS である。 - バージョン情報と環境設定の画面を撮り直した(各 2 言語)。バージョン番号と、その背後の行に出ていた誤った合計のためである。
検証
- 単体テスト 255 件、E2E スイート 21 本が全部通る。
- 放送録画 120 本を無作為抽出して
--analyzeまで通し、SmartCut 由来のエラーは 0 件。 - 4K レコーダーのディスク 3 枚・20 番組が名前で読める。2 区間カットで字幕が運ばれること、2 区間目の頭をまたぐ字幕がその頭で切られることを、別々のカットで確認した。
- HD 放送 TS のカットは、前のビルドが書いたものとバイト単位で同一。
- Linux 版と Windows 版のコマンドライン出力が md5 まで一致する。deb と tar.gz も一致する。
- AppImage を実機の画面で起動し、録画を開いてサムネイルと編集画面まで確認した。
SmartCut v0.6.3
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.6.3 は レコーダーが焼いた BD-RE を、実際にある継ぎ目で切るようにした版。レコーダーのクリップは録画を止めて再開するたびに区間が増え、カットはその継ぎ目で切る。その継ぎ目の位置が毎回ずれていた。手元の 4 枚 20 番組のうち 2 本が書き出せず、書き出せた番組も継ぎ目ごとに最後の 1 秒を失っていた。19 本が書き出せるようになった。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.6.3_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.6.3-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.6.3_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。3.9MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.6.3_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.6.3.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
継ぎ目が、カットを指示する側の時計に乗っていなかった
継ぎ目の時刻はデマルチプレクサ自身の時計で答えていた。トランスポートストリームはゼロから始まらない。その差の分だけ、継ぎ目は毎回後ろの区間の中に置かれる。あるクリップで 1.1 秒、別のクリップでは 5.0 秒だった。
結果として、手前の範囲は次の録画のピクチャを要求し、コピーは本物の継ぎ目をまたいで走る。継ぎ目をカットとして扱う仕掛けが、そもそも継ぎ目の場所を外していた。
デコーダに、継ぎ目の両側を渡していた
継ぎ目の後の区間は IDR で始まり、その IDR が「並べ替え待ちのピクチャは出すな」と言う。両側を渡すと libavcodec は手前の分を捨てる。手前の区間の最後の 1 秒は、完成して順番を待っていただけのピクチャごと消える。
そこが、継ぎ目で終わる範囲が再エンコードを指示する場所そのものである。だから 1 秒分が何も言わずに落ち、その範囲にピクチャが 1 枚も残らないときはカットが止まった(no pictures decoded)。デコーダには継ぎ目のバイトまでしか渡さず、そこで空にするようにした。待たされていたピクチャはそれで返ってくる。
継ぎ目の向こうは、最初のエントリーポイントから始める
継ぎ目と最初のエントリーポイントの間にあるのは、その区間の先行ピクチャである。**それが参照しているのは、レコーダーが止まる前の、書かれていないピクチャ。**ファイルの中に解く材料がない。普通の頭として計画すると、存在しないピクチャの再エンコードを指示することになる。
プレーヤーがエントリーポイントから再生を始めるのと同じ場所から始めるようにした。一緒に録れていた音 0.3 秒ほどはそこで捨てる。ピクチャより先まで音を残すと、範囲の残り全部がずれるからである。
継ぎ目の向こうへは、時刻でシークできない
libavformat はバイト位置で時刻を読みながら探す。**継ぎ目をまたぐと、時刻がバイトと一緒に増えなくなる。**区間の置き場所は両端を狭く読む計算から決まるので、区間どうしが重なることがある。実測で 0.46 秒。
継ぎ目の直後から始まるコピーは、1 つ前の区間の最後のエントリーポイントを先に拾う。ファイルでは手前にあって、時刻では後ろにある点である。それを「シークが行き過ぎた」と読んで止まっていた。継ぎ目はバイトも持つようにして、どのパケットがどの区間のものかは位置で決める。着地が継ぎ目より手前になるときは、継ぎ目のバイトへシークする。
実測
4 枚 20 番組を新旧そろえて通しで切った。
| 0.6.2 | 0.6.3 | |
|---|---|---|
| 書き出せた番組 | 17 / 20 | 19 / 20 |
| 出力の映像の最大の穴 | 0.751 秒 | 0.083 秒(継ぎ目 1 つでピクチャ 3 枚) |
| 置けなかったピクチャ | 68 枚 | 0 枚 |
| 継ぎ目の音の穴 | 0.38 / 0.84 秒 | 同じ |
音の穴は録画そのものにある。トランスポートストリームはある瞬間の音をピクチャの 1 秒ほど後ろに載せるので、レコーダーが書き終えた時点でその 1 秒は書かれていない。
レコーダーのクリップ以外は何も変わらない。放送 TS 3 本、参照 Blu-ray 2 枚、DVD 2 タイトルのカットは、0.6.2 が書いたものとバイト単位で同一である。
直せなかった 1 本
20 本目は、ディスクの索引が自分のストリームと食い違っているクリップである。1 つの区間(クリップの 1 割、357 点)が、指しているピクチャより 6 秒ほど早い時刻を書いていて、位置もどのピクチャにも当たらない。同じクリップの残り 5 区間は 1/1000 秒で合っている。ビットのずれが 1 つも無いので、プログラム側で直せるものではない。
できるのは、何に当たったかを表示することだけである。エントリーポイントの時刻に届いてピクチャが無かったとき、代わりに始められる最初のピクチャがどれだけ先かを表示するようにした。8 秒ずれた読みが、シークの余裕不足と取り違えられないように。
索引の時刻も繰り上げる
ついでに見つかった、ビットのずれのほう。エントリーポイントマップの粗いエントリは、位置の上位と時刻の上位を持つ。**古い上位を書いているエントリは、両方のフィールドで古い。**位置はすでに繰り上げていたが、時刻はしていなかったので、マップが 11.65 秒(細かいエントリが持つ 11 ビットの一周分)引き返して読めることがあった。
同じ直し方を時刻にもかけた。ただし時刻が増えるのは 1 つの区間の中だけである。区間ごとに時計が振り出しに戻るのはマップのずれではないので、基準は継ぎ目ごとに捨てる。ピクチャと突き合わせて確認した。4 クリップのうち 3 つは、3,592 点から 3,615 点の全部が、書いてある時刻にそこにあるピクチャを指している。直す前も後も同じである。
技術的な詳細は docs/technical/disc.ja.md に書いた。
SmartCut v0.6.2
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.6.2 は 警告なく別のものを書き出す 2 つの経路を塞いだ版。どちらも録画が壊れて出てくるのではなく、指示していないものが出てくる種類の不具合である。ひとつはバッチ出力で、前のジョブの出力設定が次のジョブに残っていた。もうひとつは CM 検出で、録画の長さを申告しないコンテナでは字幕の印が全部捨てられていた。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.6.2_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.6.2-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.6.2_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。3.9MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.6.2_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.6.2.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
前のジョブの出力設定が、次のジョブに残っていた
プロジェクトを開くとき、ファイルの settings が持っているキーだけを上書きしていた。**書かれていないキーは、直前に開いていたプロジェクトの設定がそのまま残る。**このバージョンが保存するプロジェクトは全部のキーを書くので、当たるのは決める項目が少なかった頃のバージョンが書いたファイルと、手で書いたファイルである。そして、それが効いてくる場所はバッチ出力ツールしかない。1 つのウィンドウでプロジェクトを次々に開き、しかも誰も見ていない。
実際に走らせた。ディスクを書くジョブの後ろに、出力形式を書いていないジョブを置く。後ろのジョブが求めていたのはフォルダーに 4 本のファイルである。出てきたのは BDAV ディスクで、しかも ディスク名は前のジョブに付けた名前だった(b/A/BDAV)。
ファイルを読む前に初期値へ戻し、その上に環境設定の 3 つ(接頭辞・連番・桁数)を重ね、そのあとでファイルに書かれていることだけを反映するようにした。出力について何も書いていないプロジェクトの経路が元々やっていたことで、順番を 1 つ前に出しただけである。サブフォルダーの特例もこれに吸収された。null が初期値なので、自分のフォルダーという考えが無かった頃のプロジェクトは、開けば未設定として扱われる。
長さを申告しない録画で、字幕の印が全部捨てられていた
0.6.1 で、33 ビットの時計が一周する前に打たれた印を一周分戻す処理を入れた。戻したあと録画の中に収まらないものは捨てる。この検算を、戻していない印にも掛けていた。
照合する「録画の長さ」はコンテナの申告である。分からなければ 0 が返る。プログラムストリームでは 4 ギガバイトの中身を 8 秒と申告してきた実績がある(Outline::duration のコメントにそう書いてある)。どちらの場合も、その録画の印は 1 つ残らず捨てられる。字幕リセットはロゴと無音の「代わりに」読む最優先の合図なので、何も言わずに読み落とされることになる。
戻す必要が無かった印は、そもそも疑う理由が無い。録画が運んでいるパケットに、その録画の時計が打った時刻が付いているだけである。だから検算は一周分を足した印にだけ掛けることにした。そこでは長さだけが、録画の中に戻ってきた継ぎ目と、まったく別の場所に着地した印とを分ける手段である。一周の実例と、コンテナが間違える 2 つの長さをテストに固定した。
そのほか
- バッチ出力ツールの画面を撮り直した。0.6.1 の最後で、カードが出力画面の言っていることをそのまま言うようになった(実行中の録画名と、いま作っているフレーム)。撮影がその 1 つ前だったので、古いカードが写っていた。
検証
- テストスイート 21 本(E2E 416 件)と単体テスト 239 件が通る。
- 実際の放送録画 60 本(無作為抽出)を索引まで通し、異常なし。
- バッチ出力ツールを VM の画面で走らせ、上の不具合が再現することと、直ったことを目で確認した。失敗するジョブがキューを止めないこと、読めない録画を持つジョブが赤くなって次へ進むことも併せて確認した。
SmartCut v0.6.1
スマートレンダリング対応カットツール。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーする。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いている。
0.6.1 は CM 検出の取りこぼしを 3 つ潰した版。「CM が 4 つある録画に 1 つしか出さない」という 1 本から始めて、50 本の録画でリセットの打ち方を測り、原因を 3 つに分けた。併せて、出力先に同名のフォルダがあれば枝番を付けるようにし、入力画面のまま保存したプロジェクトが、まだ誰も決めていない出力設定を抱え込まないようにした。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.6.1_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要 |
SmartCut-0.6.1-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE が不要 |
smartcut_0.6.1_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。3.9MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れる |
SmartCut_0.6.1_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要 |
smartcut-portable-x64-0.6.1.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行 |
**FFmpeg を別途入れる必要があるのは deb だけ。**ほかの配布物はすべて同梱している。
番組の切れ目にしか印を打たない局がある
CM 検出は 3 つの合図を優先順位で 1 つだけ読む。字幕リセット、無ければロゴ、それも無ければ無音である。リセットは放送局の設備が継ぎ目に打った刻印で、ほかの 2 つが推測であるのに対してこれは事実だから、あれば迷わずそれを読む。
**その前提は、印が録画全体を読み切っていることである。**ある BS 局はそうではなかった。CM の両端だけを打ち、その間は打たない。継ぎ目ごとに打つ局が 30 分で 26 個出すところ、この局は 6 個である。6 個を他の 2 つの代わりに読んだ結果、CM が 4 つある録画に 1 つしか出さなかった。ロゴは強く出ていて 4 つとも当てていたのに、一度も見ていない。
**2 種類の局を分けるのは、CM の内側にある印である。**15 秒ちょうど隣り合うリセットのことで、CM が 1 本終わって次が始まる場所を指す。両端はどちらの局も打つので、両端を見ても分からない。
| 30 分あたりの隣接ペア | |
|---|---|
| 継ぎ目ごとに打つ 3 局(24 本) | 5 〜 30 |
| 両端だけ打つ局(26 本) | 0 〜 2 |
3 個以上を求めることにした。空いているところの真ん中である。足りなければ、印を 1 つも持たない録画とまったく同じように扱う。リセットの総数(5〜10 対 18〜35)や最長のリセット列でも分かれるが、前者は録画の長さで割る必要があり、後者は余裕が 1 しかない。
目視で確かめた 2 本は、どちらも印が拾えていなかった 2 つのブロック(頭のスポットと、末尾の番宣・通販)が増えた。221 秒と 305 秒の CM が残っていたことになる。失ったものは無い。
両端しか打たれていない、2 分より長い CM が捨てられていた
無音を繋ぐ格子は、隣どうしを 8 単位(2 分)まで許している。偶然に連鎖ができるのが、あの読み方が防ぐべきことのすべてだからである。リセットも同じ 8 に縛っていた。継ぎ目ごとに打つ局では CM 全体が 1 単位ずつの連鎖になるので上限に触れないが、両端しか打たない局では CM 全体が 1 つの間隔になる。
ある局のアニメ枠を 1 クール分測った。68 本のうちリセットが 3 個以上あるのは 26 本。上限を上げて増えたブロックは **20 個、すべて 135 秒(9 単位)か 150 秒(10 単位)**だった。上限を 20 まで試しても 11 単位以上は 1 つも現れない。この 2 つがその局の中 CM の定尺で、CM と CM の間の本編は 25 単位以上ある。
上限を 12(3 分)にした。継ぎ目ごとに打つ局は影響を受けない。テストに固定してある BS フジの 134.9 秒の CM も 9 単位だが、印が 1 単位ずつ並んでいるので危なかったことは一度も無い。
時計が一周する前の印が、逆向きのブロックになっていた
トランスポートストリームは 33 ビット・90 kHz の時計で時刻を運び、26 時間ほどで一周する。測った 50 本のうち 1 本がその点をまたいでいて、またいだあとのリセットが -93848.7 秒として返っていた。並べ替えると先頭に来る。先頭の単独の印は「録画の頭からそこまでが CM」と読まれるので、始まりより 26 時間前に終わるブロックになっていた。
これは本物の継ぎ目だった。一周分戻すと 1807.1 秒の録画の 1595.0 秒、その番組が終わって番宣が始まる場所である。別に読んだロゴは同じ境界を 1599.3 秒と言っている。印が過去でなくなるまで一周分を足し、それでも録画の中に収まらないものを捨てるようにした。
**検出のキャッシュ版数を上げた。**以前の答えで覚えている録画は、次に開いたときに読み直される。手でキャッシュを消す必要は無い。
出力先に同名のフォルダがあれば枝番を付ける
自分のフォルダに書き出す実行は、最初のカットを書くときにそのフォルダを作る。同名のフォルダが既にあると、**同じ一覧・同じ接頭辞・同じ連番なので、前回のファイルの上に今回のファイルがそのまま重なる。**一言も無く消える。
名前に枝番を付けるようにした。night の次は night-2、night-3 である。実行が書き込むフォルダすべてについて空いている名前を選ぶ。出力先を空欄にするとカットは元の録画の隣に書かれるので、3 つのフォルダから集めた一覧なら作るフォルダも 3 つになる。一覧に対する設定は 1 つでなければならない。
画面の設定は数分前のものかもしれないので、実行の直前にもう一度確かめ、枝番が付いたときはそれを記録する。欄には入力した名前が残り、横に 同名のフォルダーあり → night-2 と出る。欄を書き換えると、入力中の文字を奪うことになるうえ、枝番を名前に戻すと次は night-2-2 になる。
**ディスクは対象外である。**2 回目の出力はディスクに足されるのが仕様で、1 週間かけてディスクを埋められるのはそのためである。フォルダが既にあるのは問題ではなく目的である。
入力画面で保存したプロジェクトは、出力設定を持たない
入力画面のまま保存したプロジェクトには、出力の指定が無い。そのとき保持しているのは、初期値と、環境設定で決めた書き出し名と、前回から引き継いだ設定である。**どれもこの作業について決めたことではない。**書き込めば標準の答えではなくそのプロジェクトの答えになり、環境設定を変えたあともファイルが古い設定を保持し続ける。
出力設定画面のコントロールを実際に操作したときだけ書くようにした。それまではファイルに出力の記述が無く、開けば標準の初期値をもう一度読む。画面を開いただけは操作に入らない。フォルダー名やディスク名は録画から自動で埋まるもので、次に開いたときもまた埋まる。
バッチだけは例外で、バッチに登録 はキューに渡す複製へ必ず出力設定を書く。ジョブは「いまのウィンドウが書き出すとおり」に書き出すものであって、数時間後に別プロセスの環境設定から組み立て直されては困る。
そのほか
- バッチ出力ツールで、ジョブ番号をカードの中央に置いた。カードの高さは中身で変わるので、上揃えだと番号の位置が行ごとにずれていた。
ドキュメント
docs/technical/cm-detection.ja.md に今回の測定を 3 節足した。ユーザー向けのCM 検出は、「字幕の印があれば必ずそれを使う」という記述が嘘になったので書き換えた。画面の使い方とプロジェクトにも枝番と出力設定の話を足し、バッチ出力ツールの画面を撮り直した。