Unityの認定資格を取得しようと思い、学習バンドルを購入しました。
ところが手続きの際、たぶん「アメリカ人」として登録してしまったようで、
提供された動画コンテンツがすべて英語音声かつ字幕なしという状態になってしまいました。
英語のリスニングにも苦戦する中で、「せめて英語字幕があれば」と思い、
.mp4動画から自動で音声を文字起こしし、英語字幕付き動画を出力するPythonツールを作ってみました。
入力と出力
- 入力:英語音声の .mp4 動画
- 出力:英語字幕(SRT形式)を動画に焼き込んだ .mp4
使用ライブラリ
- openai-whisper: 音声をテキストに文字起こし(ローカル実行だと無料で使える)
- moviepy: 音声を抽出(mp4→wav)
- ffmpeg: 字幕(SRT)を動画に焼き込む
セットアップ
仮想環境と依存パッケージ
# 仮想環境を作成
python -m venv venv
source venv/bin/activate # Windowsは venv\Scripts\activate
# 必要パッケージをインストール
pip install openai-whisper moviepy ffmpeg-python
ffmpegのインストール
# macOS
brew install ffmpeg
プロジェクト構成
TranslateMovie/
├── input.mp4
├── en_subtitled_video_generator.py
├── output/
│ ├── audio.wav
│ ├── subtitles.srt
│ └── output_with_subs.mp4
仕組みの概要
- mp4 → wav へ音声抽出(MoviePy)
- Whisperで音声→英語テキストに変換
- Whisperのセグメント情報をもとに SRT ファイルを作成
- FFmpegで動画に英語字幕を焼き込み
コア処理(コードの要点)
MP4 → WAV
from moviepy.editor import VideoFileClip
video = VideoFileClip("input.mp4")
video.audio.write_audiofile("output/audio.wav")
Whisperで文字起こし
import whisper
model = whisper.load_model("base")
result = model.transcribe("output/audio.wav")
SRTファイルを作成
def format_timestamp(seconds):
h = int(seconds // 3600)
m = int((seconds % 3600) // 60)
s = int(seconds % 60)
ms = int((seconds - int(seconds)) * 1000)
return f"{h:02}:{m:02}:{s:02},{ms:03}"
with open("output/subtitles.srt", "w", encoding="utf-8") as f:
for i, seg in enumerate(result["segments"], start=1):
f.write(f"{i}\n")
f.write(f"{format_timestamp(seg['start'])} --> {format_timestamp(seg['end'])}\n")
f.write(f"{seg['text']}\n\n")
FFmpegで字幕を動画に焼き込み
ffmpeg -i input.mp4 -vf "subtitles=output/subtitles.srt" -c:a copy output/output_with_subs.mp4
実行スクリプト
ルートディレクトリにinput.mp4を配置して、以下のスクリプトを実行すると英語字幕付きの動画ができあがるはずです。
import os
import whisper
from moviepy.editor import VideoFileClip
import subprocess
# 設定
input_video_path = "input.mp4"
extracted_audio_path = "output/audio.wav"
output_srt_path = "output/subtitles.srt"
output_video_path = "output/output_with_subs.mp4"
# 前に作成した動画などの削除処理
for path in [extracted_audio_path, output_srt_path, output_video_path]:
if os.path.exists(path):
os.remove(path)
print(f"🧹 削除しました: {path}")
# タイムスタンプのフォーマット変換(Whisperの時間 → SRT形式)
def format_timestamp(seconds: float) -> str:
h = int(seconds // 3600)
m = int((seconds % 3600) // 60)
s = int(seconds % 60)
ms = int((seconds - int(seconds)) * 1000)
return f"{h:02}:{m:02}:{s:02},{ms:03}"
# ステップ1:mp4 → wav
print("🎞️ MP4 → WAV に変換中...")
video = VideoFileClip(input_video_path)
video.audio.write_audiofile(extracted_audio_path)
# ステップ2:WAV を Whisper で文字起こし
print("🗣 Whisper による英語文字起こし中...")
model = whisper.load_model("base")
result = model.transcribe(extracted_audio_path, task="transcribe")
# ステップ3:SRTファイルとして保存
print("💬 SRT字幕を保存中...")
with open(output_srt_path, "w", encoding="utf-8") as f:
for i, segment in enumerate(result["segments"]):
start = segment["start"]
end = segment["end"]
text = segment["text"]
f.write(f"{i+1}\n")
f.write(f"{format_timestamp(start)} --> {format_timestamp(end)}\n")
f.write(f"{text}\n\n")
# ステップ4:ffmpegで字幕を動画に焼き付け
print("📽 字幕を動画に焼き込み中...")
subprocess.run([
"ffmpeg",
"-i", input_video_path,
"-vf", f"subtitles={output_srt_path}:force_style='FontName=NotoSansCJKjp'",
"-c:a", "copy",
output_video_path
])
print("✅ 完了!字幕付き動画:", output_video_path)
おわり
最後まで読んでいただきありがとうございました。
英語字幕があるだけでもありがたいのですが、まだえいごだけだt理解しづらいところがあるので
次は日本語字幕バージョンを作ってみようと思います。