0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

字幕自動化 _ Whisper × Deep Translator × FFmpeg 字幕焼き込みを Colab で全自動化する方法

Last updated at Posted at 2024-12-30

Whisper × Deep Translator × FFmpeg 字幕焼き込みを Colab で全自動化する方法

最近、OpenAI の Whisper を使った動画文字起こしが注目されています。英語の動画を日本語に翻訳したいケースも多いですよね。そこで今回は、Google Colab を使って一気に以下を行うサンプルを紹介します。

  1. Whisper で動画から英語文字起こし
  2. Deep Translator で日本語に翻訳
  3. SRT → ASS → FFmpeg で字幕を動画に焼き込み
  4. 日本語はもちろん、英数字も見やすいフォントに
  5. Colab で完結して手軽!

前提

  • Google Colab の環境を想定
  • video.mp4 のような動画ファイルがダウンロード可能(あるいは Colab にアップロード済み)
  • 実行時に、依存ライブラリがインストールされるのを待つため、多少の時間がかかります

コード全文

以下を Colab のセル にコピー&ペーストすれば、すべてのステップが完了します。

################################################################################
#  0) Whisper キャッシュクリア (推奨)
#     うまくいかない場合でもキャッシュ削除すると再ダウンロードが走り、
#     SSLエラー等が解決することがあります
################################################################################
!rm -rf ~/.cache/whisper


################################################################################
#  1) 必要なライブラリをインストール
################################################################################
!pip install yt-dlp
!pip install ffmpeg-python
!pip install whisper
!pip install deep-translator

# 古い whisper を削除 → 最新版を GitHub から導入 (任意)
!pip uninstall -y whisper
!pip install git+https://github.com/openai/whisper.git

# 日本語フォント (Noto Sans JP) および Noto Sans をインストール
!apt-get install -y fonts-noto
!apt-get install -y fonts-noto-cjk

import subprocess
import yt_dlp
import whisper
from deep_translator import GoogleTranslator


################################################################################
#  2) 動画をダウンロード (例: X/Twitter 動画)
#
#  今回は Twitter の URL を例示していますが、
#  すでに mp4 があるなら、このステップはスキップ可。
################################################################################
twitter_url = "https://x.com/dfinity/status/1870061438384959498"  # 例: Twitter の動画URL
video_filename = "video.mp4"

ydl_opts = {
    'format': 'best',
    'outtmpl': video_filename
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
    ydl.download([twitter_url])

print("動画がダウンロードされました:", video_filename)


################################################################################
#  3) Whisper で英語文字起こし
################################################################################
model = whisper.load_model("base")
result = model.transcribe(video_filename)
print("【Whisper英語文字起こし】\n", result['text'])


################################################################################
#  4) Deep Translator で英語 → 日本語 翻訳
################################################################################
segments = result['segments']
translated_texts = []

for seg in segments:
    en_text = seg["text"].replace("\n", " ")
    try:
        ja_text = GoogleTranslator(source="en", target="ja").translate(en_text)
    except Exception as e:
        print("翻訳エラー:", e)
        ja_text = "[翻訳エラー]"
    translated_texts.append(ja_text)


################################################################################
#  5) SRTファイル作成 (日本語向けに行長をある程度長めに設定)
################################################################################
def format_timestamp(seconds):
    hrs, secs = divmod(seconds, 3600)
    mins, secs = divmod(secs, 60)
    millis = int((secs - int(secs)) * 1000)
    return f"{int(hrs):02}:{int(mins):02}:{int(secs):02},{millis:03}"

def wrap_text_japanese(text, max_len=30):
    """
    日本語向けに、一定文字数ごとに強制的に改行する例。
    今回は 1 行を 30 文字に設定。
    """
    if not text:
        return ""
    lines = []
    current_line = ""
    for char in text:
        current_line += char
        # 30文字たまったら改行
        if len(current_line) >= max_len:
            lines.append(current_line)
            current_line = ""
    if current_line:
        lines.append(current_line)

    return "\n".join(lines)

def create_srt(segments, texts, output_file="subtitles.srt", max_line_length=30):
    with open(output_file, 'w', encoding='utf-8') as f:
        for i, (segment, text) in enumerate(zip(segments, texts)):
            start, end = segment['start'], segment['end']
            wrapped_text = wrap_text_japanese(text, max_line_length)

            f.write(f"{i+1}\n")
            f.write(f"{format_timestamp(start)} --> {format_timestamp(end)}\n")
            f.write(f"{wrapped_text}\n\n")

srt_file = "subtitles.srt"
create_srt(segments, translated_texts, srt_file)
print("SRTファイルを作成しました:", srt_file)


################################################################################
#  6) SRT → ASS 変換
################################################################################
def convert_srt_to_ass(srt_file, ass_file):
    cmd = [
        "ffmpeg", "-y",
        "-f", "srt",
        "-i", srt_file,
        "-c:s", "ass",
        ass_file
    ]
    try:
        subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        print(f"SRT to ASS conversion successful: {ass_file}")
    except subprocess.CalledProcessError as e:
        print("Error during conversion:", e.stderr.decode("utf-8"))

ass_file = "subtitles.ass"
convert_srt_to_ass(srt_file, ass_file)


################################################################################
#  7) ASS 字幕を焼き込む (WrapStyle=2 で自動折り返し)
################################################################################
output_video = "output_video.mp4"

cmd = [
    "ffmpeg", "-y",
    "-i", video_filename,
    "-vf",
    (
        "subtitles=subtitles.ass:"
        "force_style='FontName=Noto Sans,FontSize=20,"
        "MarginL=100,MarginR=100,WrapStyle=2'"
    ),
    "-c:a", "copy",
    output_video
]

try:
    subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print("字幕を焼き込んだ動画を生成しました:", output_video)
except subprocess.CalledProcessError as e:
    print("Error during video processing:", e.stderr.decode("utf-8"))


################################################################################
#  8) Colab から ダウンロード (任意)
################################################################################
# from google.colab import files
# files.download(output_video)

print("\nすべての処理が完了しました。")

コードの解説

  1. Whisper のキャッシュ削除

    • !rm -rf ~/.cache/whisper で、キャッシュ破損などを避けるために毎回削除します。
  2. ライブラリインストール

    • yt-dlp, ffmpeg-python, whisper, deep-translator を導入
    • Whisper の既存バージョンをアンインストール → GitHub 最新版を入れているのは、Colab でエラーを回避するための対策です
  3. 日本語フォントをインストール

    • Noto Sans, Noto Sans JP は日本語・英語・数字も幅広く対応
  4. 動画ダウンロード

    • ここでは yt-dlp を使い、Twitter(X) の動画を例示しています
    • すでにローカルに mp4 があればこのパートはスキップして構いません
  5. Whisper (base) モデルで英語文字起こし

    • 大きなモデルもありますが、Colab で試すには base が軽量で安定です
  6. Deep Translator で翻訳

    • 文字起こし結果の英語を API で日本語に変換
    • 無料枠内で実行できる範囲を超えると制限される場合もあります
  7. SRT 作成 + 日本語ラッピング

    • wrap_text_japanese() 関数で「30文字たまったら改行」という単純なロジック
    • 全角・半角が混在すると行幅は多少前後しますが、実用としては十分です
  8. SRT → ASS 変換 → FFmpeg で焼き込み

    • ffmpeg-vf subtitles=...:force_style='...' を指定することで
      • フォント (Noto Sans)、フォントサイズ (20)、左右マージン (100)、WrapStyle=2 (自動折り返し) を強制しています
  9. 結果ダウンロード (オプション)

    • Colab 上で生成した output_video.mp4 をダウンロードする場合は、google.colab.files.download(output_video) を利用

うまくいかない時のヒント

  • Twitter の動画 URL が無効の場合
    • そのまま yt-dlp でエラーが出るので、ほかの動画リンクを試す
  • Whisper ダウンロード時に SSL エラー
    • キャッシュ削除や Colab ランタイム再起動を試す
  • 翻訳 API の制限
    • エラーになった場合は翻訳回数の制限を超えている可能性があるので、DeepL 等 別の翻訳手段を探す

まとめ

このように Google Colab 上でスクリプトを一気に実行すれば、英語字幕から日本語訳まで自動で作成して、最終的には動画へ焼き込みまでしてくれます。日本語は文字幅があるため手動で適度に改行した方が見やすいことも多いですが、今回のスクリプトでも簡単な整形はカバーできるはずです。
ぜひ使いやすいようにカスタマイズしてみてください。


0
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?