字幕が一文字も出ていない動画を、AIは「出ています」と答えた話
困ったこと
30秒の縦長ショート動画を、原稿づくりから声・映像・音楽・字幕まで全部AIで作る流れを組んでいた。最後の工程が字幕の焼き付けだった。専用の機能に「この日本語フォントを使え」と指定して、テロップを載せた。
自分では出来上がりを目で見られないので、画像を読めるAIに「字幕は出ていますか」と尋ねた。「出ています」という返事だった。そのまま人に見せたら、一文字も入っていなかった。
原因は地味だった。指定したフォント名が無視され、日本語を持たない別のフォントに勝手に差し替えられていた。文字を描こうとしたが、描ける形が一つもなく、何も描かれないまま完成していた。手がかりはあった。字幕なし版とファイルの重さがぴったり同じだったのだ。何も足されていない証拠が、最初から目の前にあった。
どう解決したか
フォントを「名前で指定する」のをやめ、「置き場所を直接指す」別の機能に切り替えた。名前で呼ぶと、途中で誰かが解釈してすり替える余地が残る。現物を指させば、すり替えようがない。
同じ考え方が、もう一つの悩みも解いた。字幕のタイミングが、後半になるほどズレていく。理由は、字幕を「映像の場面の切れ目」に合わせていたことだった。けれど本当の時計は、ナレーション音声のほうにある。音声から発話の区切りを機械で聞き取って実際の時刻を測り、その時刻に映像の長さと字幕の両方を合わせ直した。全部そろった。
何が変わったか
「AIに確かめさせる」が万能ではないと分かった。見えていないものを、見たと答えることがある。だから確認は、言葉の返事ではなく数字で取りにいくようにした——ファイルの重さを見比べる、音声から時刻を測る。
そして基準を決めるときは、いちばん動かないものを選ぶようにした。映像の長さは後からいくらでも伸び縮みするが、喋ってしまった音声は伸び縮みしない。ズレを一つずつ直すより、「何に合わせるか」を変えるほうがずっと早かった。
<details> <summary>▶ 技術的にどう作ったか</summary>
- 対象: 30秒・縦1080×1920のショート動画を全自動生成する7工程パイプライン(原稿→TTS→フック映像→demo画面→BGM→結合→字幕)
- 字幕の空焼き付け:
subtitles(libass) フィルタにforce_style='FontName=...'を渡してもフォント名が解決されず、日本語非対応フォントへfallbackして描画ゼロになる(fontsdir指定でも再現)。drawtextフィルタでfontfile=にフォントファイルの絶対パスを直接渡す方式へ切替えて解決(fontconfig非依存) - 検証の失敗: 生成物の目視確認を画像認識AIに委ねたところ「字幕あり」と誤答。字幕なし版とビットレートが同一だった点がフィルタ無視の客観的な証拠であり、返答ではなくそこを見るべきだった
- タイミング同期: 字幕を映像シーン境界に合わせると累積ズレが発生。音声認識(whisper)でナレーションから発話区間を実測し、その絶対時刻を基準に映像シーン長と字幕を両方再構成する方式が最終解。認識されたテキスト自体は誤りが多いが、タイミングは正確なので原稿テキストで上書きして区間だけ採用
- 他のハマりどころ: 動画生成APIが縦解像度の指定を無視する(cropとscaleで後段変換)/ターミナル録画は行の折返しで縦クロップ時に読めなくなる(静的画像の直描画へ変更)/
drawtextはprintf形式展開するため文中の半角%が構文エラーになる(全角に置換)/フィルタを10個以上同時に並べると出力尺が壊れる(前半後半の2パスに分割) - 記録: 詳細は個人ナレッジベースの dev-knowledge-shorts プロジェクト配下(2026-08-06 制作パイプライン知見まとめ・2026-08-08 字幕タイミング最終解の追記を含む)
</details>