SmartCut v0.5.11
スマートレンダリング対応のカットツールです。**カット点にかかる部分 GOP だけを再エンコードし、残りはビット単位でそのままコピーします。**放送録画(MPEG-2 TS)から CM を落とす用途を主眼に置いています。
0.5.11 では、渡されたファイルを疑って読むようにしました。録画も、それと同じ名前の索引も、開いたプロジェクトも、書いたのは SmartCut ではありません。壊れていれば理由を示して突き返すべきところで 5 か所がパニックし、1 か所はプロセスごと落ちていました。その 6 つを直し、ウィンドウにコンテンツセキュリティポリシーを与えています。機能の増減はありません。
ダウンロード
| ファイル | 対象 |
|---|---|
SmartCut_0.5.11_amd64.AppImage |
Linux x64。glibc 2.39 以上(Ubuntu 24.04 / Debian 13 / Fedora 40 以降)。FUSE が必要です |
SmartCut-0.5.11-linux-x86_64.tar.gz |
Linux x64 可搬版。解凍して ./smartcut。中身は AppImage と同じ一式で、FUSE は不要です |
smartcut_0.5.11_amd64.deb |
Debian 13 / Ubuntu 25.04 以降。3.4MB。GUI を smartcut、コマンドライン版を smartcut-cli として入れます |
SmartCut_0.5.11_x64-setup.exe |
Windows x64 インストーラ。WebView2 ランタイムが必要です |
smartcut-portable-x64-0.5.11.zip |
Windows x64 可搬版。解凍して smartcut.exe を実行します |
FFmpeg を別途入れる必要があるのは deb だけです。ほかの配布物には同梱しています。
壊れた索引は、プログラムを止めずに突き返します
ディスクの表も、ディスクが入っているイメージも、SmartCut が録画と同じ名前で置くシーク索引も、読む側から見ればどれも「誰かに渡されたファイル」です。そのうちの 6 つが、壊れたものを与えられたときに解体を最後まで進めてしまっていました。それぞれに再現するテストを添えています。
- パーティションマップ表が 1 エントリに満たない UDF イメージ。 エントリ長を示す 2 バイトを確かめてから 5 バイト目を読んでいたので、2 バイトの表で
Image::openが終わります。.isoを開く経路すべてが通るところです。いまはエントリをまず表から切り出し、64 バイトである種別には 64 バイトを要求します。 - マジックの後ろに何も無い DVD の索引。 DVD を読む 2 つの表は決まった位置の語で見つけるので、
DVDVIDEO-VMGの 12 バイトだけが前に立っていました。64 バイトのファイルで足りてしまいます。短い表には 0 を返すようにし、0 は既にある検査(セクタ 0 の表、端が繋がらない鎖)に当たります。 - 持っている数より多くのサブピクチャを名乗るタイトルセット。 数はバイト 1 つ、その後ろの表は 1 エントリ 6 バイトなので、表の始まる場所で終わっている索引でも 32 本あると言えてしまいます。
- 入っている索引の外を指す鎖の表。 パレットの読み取りが空のスライスから数を取っていました。
- スタートコードが 2 つ続く VC-1 パケット。 最初のユニットのペイロードが 2 つ目のスタートコードの 1 バイト手前から始まります。VC-1 のパケットはピクチャヘッダを探すため、すべてここを通ります。
- シーク索引。 40 バイトで 1 兆個のアクセスポイントを宣言すると、1 つも読まないうちにベクタを確保しようとします。この大きさの確保は失敗ではなくアボートなので、返すエラーも、ウィンドウが捕まえるものも残りません。数は、それを収めるだけのバイトが残っているかで疑うようにし、ピクチャ種別の表の長さ検査は
checked_mulで掛けます。ラップして自分と辻褄が合ってしまわないようにするためです。
イメージの読み取り側では同じ考えをバッファにも当てました。エクステントは長さを 30 ビットで持つので、記述子 1 つで 1GB を要求できます。イメージの外に出る範囲は、読む前に突き返します。199 テスト通過です。
ウィンドウにコンテンツポリシーを与え、プロジェクトを疑って読みます
ウィンドウにはコンテンツセキュリティポリシーがありませんでした。withGlobalTauri を載せたページでこれが無いということは、そこに入り込んだスクリプトがバックエンドのコマンドを全部呼べるということで、そのうち 3 つは呼び出し側の指定したパスにファイルを書きます。**入り込む経路は見つかっていません。**一覧は描く名前をすべてエスケープし、残りは textContent を通ります。壊れた鍵の修理ではなく、同じ扉の 2 つ目の鍵です。
default-src 'self' を基本に、バックエンドが base64 で渡す画像のために data:、コマンドそのもののために ipc: と http://ipc.localhost、オブジェクト・ベース URI・フォームの送信先・フレーム埋め込みには 'none' を指定しています。
入れてみて本物の不具合が 1 つ出ました。これが入れる理由でもあります。出力画面は進捗バーを style="width:…%" とマークアップに書いていて、マークアップ中の style 属性はどんな厳しさのポリシーでも真っ先に止まります。幅の無いブロックは親を埋めるので、**どの行のバーも満杯に描かれていました。**待機中も、実行中もです。いまはプロパティで幅を設定します。
プロジェクトファイルは、一覧の中で唯一「他人が書いたことのありうるもの」です。しかもその行は誰の指示も無しに開かれます。一覧が出た瞬間に索引のレーンが走り出すためです。エンジンは知らない名前をそのまま libavformat に渡し、libavformat はファイル以外のものを大量に開きます。コマンドラインではそれが要点ですが、ウィンドウでは違います。プロトコルを名乗る行は読み込まず、いくつ外したかを表示するようにしました。ドライブレターはプロトコルではありませんし、ウィンドウが自分でマウントポイントに直す共有の書き方も違います。
最後にロックです。その後ろにあるのは何が開いているかのキャッシュだけなのに、Mutex::lock は保持したままパニックしたスレッドが 1 つあれば、以後ずっと拒み続けます。読めない録画 1 本で、フィルムストリップもプレビューも一覧も、起動し直すまで何も答えなくなり得ます。いまは汚染を跨ぎ、次に開いたものがその中身を上書きします。
直したもの
- 編集画面が「録画を読み込み中です」のまま戻らないことがありました。 バッジは「—」、無劣化点へ吸着は灰色、書き出しプランは出ないままです。画像もカウンタもフィルムストリップもカット自体も動いているのに、です。開く処理のどの段もプランパネルを予約しますが、ウィンドウが
openingの間その問い合わせは「読み込み中」と答えます。最後の予約がその答えを持ち帰った時点で、代わりに問い合わせるものはもう残っていません。間に合うかどうかを決めていたのは、最後の予約と開き終わりの間にある 120ms タイマ付きのピクチャ復号でした。小さい録画は間に合い、1600 ピクセル幅のウィンドウに 1440x1080 は毎回間に合いません。走査が並んだ後にもう一度問い合わせるようにしました。 - ドキュメントを実測で洗い直しました。 README の先頭の動画を両言語で撮り直し(同じ練習用録画、同じ 2 カット、133.91 秒コピー・0.57 秒再エンコード、6743 フレーム中 17 フレーム)、内部リンク・パス・環境変数・コマンドラインオプションを機械的に突き合わせています。
--indexが取るのは 4 つで既定はauto、など 5 か所を直しました。テストの数も 20 スイートを実際に走らせて数え直しています。ディスクは 38、索引の実装を差し替えた実行は 15 のうち 11 です(トランスポートストリームにコンテナのシーク表は無いので、4 つは自分で飛ばします)。