msedge-ttsとffmpegでAI動画を0円生成する実践手順
月コスト0円で動画生成パイプラインを作るための最小実装

YouTube Shorts や TikTok 用の動画を量産したい場合、商用のAI動画生成サービスは月 $20-100 が普通です。しかし、Microsoft Edge に内蔵されている TTS (Text-to-Speech) と ffmpeg を組み合わせれば、ナレーション + 字幕 + BGM 付きの動画を完全無料で量産できます。私は ai-pick 記事自動生成 Worker でこの構成を使い、毎日1本の YouTube Shorts (約 36秒MP4) を自動生成しています。月コストは0円、生成時間は1本あたり約 2分です。実装の全構成を共有します。
必要なツールと環境
必要なソフトウェアは3つだけです。すべて無料で揃います。
- Node.js 18+: スクリプト実行環境
- msedge-tts: npm パッケージ、Microsoft Edge内蔵TTSエンジンへのインターフェース
- ffmpeg: 動画エンコード、ダウンロードして PATH に通す (Windows なら gyan.dev版が安定)
追加で BGM 用のロイヤリティフリー音源を数曲用意します。DOVA-SYNDROME や YouTube オーディオライブラリ から無料で取得できます。
パイプライン全体像
動画1本を生成するフローは4ステップです。
- 台本生成: シーン構造 (5シーン × 約6秒) を Claude/Gemini で生成
- ナレーション生成: msedge-tts で各シーンの音声 .wav ファイルを生成
- 映像生成: HTML + Playwright で各シーンの静止画 PNG を生成
- 合成: ffmpeg で 静止画 + ナレーション + BGM をMP4に合成
合計 36秒の動画が、1分30秒〜2分で完成します。
msedge-tts によるナレーション生成
Microsoft Edge の TTS は無料・高品質・日本語ボイスが豊富です。私は「ja-JP-NanamiNeural」(女性ボイス) を主に使っています。
// scripts/generate-narration.mjs
import { MsEdgeTTS, OUTPUT_FORMAT } from 'msedge-tts';
import { writeFile } from 'node:fs/promises';
async function generateNarration(text, outputPath) {
const tts = new MsEdgeTTS();
await tts.setMetadata(
'ja-JP-NanamiNeural',
OUTPUT_FORMAT.AUDIO_24KHZ_96KBITRATE_MONO_MP3
);
// 話速を少し落として聞き取りやすく
const ssml = `<speak version="1.0" xml:lang="ja-JP">
<voice name="ja-JP-NanamiNeural">
<prosody rate="-5%">${text}</prosody>
</voice>
</speak>`;
const buffer = await tts.toStream(ssml);
await writeFile(outputPath, buffer);
}
// 使用例: シーン3の台本「お金を一切預けないという基本ルール」を音声化
await generateNarration(
'お金を一切預けないという基本ルール。',
'output/scene-03.mp3'
);
このコードで、約 5秒のテキストが 5-7秒の高品質日本語ナレーションになります。1シーンあたり処理時間は約 2-3秒、ファイルサイズは約 100KB です。
HTML + Playwright で映像 (静止画) 生成
動画素材は静止画にしておくことで、ffmpeg の処理が高速になります。HTMLでデザインしたシーンを Playwright でスクリーンショットすると、CSS の自由度を活かしてリッチな映像が作れます。
// scripts/render-scenes.mjs
import { chromium } from 'playwright';
import { mkdir } from 'node:fs/promises';
async function renderScene(htmlContent, outputPath) {
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 1080, height: 1920 } // Shorts 縦動画
});
await page.setContent(htmlContent);
await page.waitForLoadState('networkidle');
await page.screenshot({ path: outputPath, type: 'png' });
await browser.close();
}
// シーン3の HTML (実際には Gemini で動的生成)
const sceneHtml = `
<style>
body { margin: 0; background: linear-gradient(135deg, #1e293b, #0f172a); }
.scene { width: 1080px; height: 1920px; display: flex;
align-items: center; justify-content: center; color: white;
font-family: 'Hiragino Sans', sans-serif; }
h1 { font-size: 96px; font-weight: 900; text-align: center; padding: 0 80px; }
</style>
<div class="scene"><h1>お金を一切預けない基本ルール</h1></div>
`;
await renderScene(sceneHtml, 'output/scene-03.png');
ffmpeg で合成
静止画 + ナレーション + BGM を1本のMP4に合成する ffmpeg コマンドです。BGMは音量を下げてミックスします。
# 1シーンを動画化 (静止画 + ナレーション)
ffmpeg -loop 1 -i scene-03.png -i scene-03.mp3 \
-c:v libx264 -tune stillimage -pix_fmt yuv420p \
-c:a aac -b:a 192k \
-shortest scene-03.mp4 -y
# 5シーンを連結
ffmpeg -f concat -safe 0 -i scenes-list.txt -c copy combined.mp4 -y
# BGM を音量0.22でミックス
ffmpeg -i combined.mp4 -i bgm.mp3 \
-filter_complex "[1:a]volume=0.22[bgm];[0:a][bgm]amix=inputs=2:duration=first" \
-c:v copy final.mp4 -y
BGM音量 0.22 は私が試行錯誤で見つけた数値で、ナレーションを邪魔せず雰囲気だけ出る絶妙な設定値です。これより大きいとナレーションが聞き取りにくく、小さいと「音楽が無いみたい」になります。
運用してみての効果
この構成を ai-pick 記事自動生成 Worker に組み込み、毎日 15:09 の自動実行で1本ずつ YouTube Shorts を生成・投稿しています。月60本ペースの動画量産が月コスト0円で回り続けます。1本あたりの処理時間は約 90秒、エラーは月1-2回程度 (ほぼ Playwright のフォント描画でハマるケース)。
商用AI動画生成 (Higgsfield、Synthesia 等) は確かに動的な動画を作れますが、月数千円のコストがかかります。「とりあえず量を作る」段階では、msedge-tts + ffmpeg の構成で十分実用できます。本格的に動きのある動画が必要になってから有料サービスへの移行を検討すれば良いです。
AIワークフローの他の実装例は AIワークフローカテゴリ に、SNS自動投稿基盤は 自動化レシピカテゴリ に蓄積しています。