0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで英語動画に英語字幕を自動生成してみた【Whisper × MoviePy × FFmpeg】

Posted at

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

仕組みの概要

  1. mp4 → wav へ音声抽出(MoviePy)
  2. Whisperで音声→英語テキストに変換
  3. Whisperのセグメント情報をもとに SRT ファイルを作成
  4. 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理解しづらいところがあるので
次は日本語字幕バージョンを作ってみようと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?