【BGM付き完全自動化】Pythonとffmpegでオリジナルショート動画を量産する方法


目次

【BGM付き完全自動化】Pythonとffmpegでオリジナルショート動画を量産する方法

動画編集はもう終わり!Pythonとffmpegで、動画素材のランダム結合からBGM追加、別名保存まで全自動化。魅力的なオリジナルショート動画を量産しませんか?

なぜ自動BGM付きショート動画作成プログラムを開発したのか

SNSで目を引くショート動画にBGMは不可欠です。しかし、大量の動画に一つ一つ手作業でBGMを追加するのは非常に手間がかかります。そこで、

  • ランダムに選んだ動画素材に、さらにランダムなBGMを自動で追加したい
  • 編集時間を大幅に削減し、コンテンツ作成の効率を極限まで高めたい
  • プログラミングの力で、より魅力的なショート動画を自動生成したい

という強い思いから、この全自動BGM付きショート動画作成プログラムを開発しました。

完成した自動BGM付きショート動画作成プログラムの全貌

Python

import os
import random
import subprocess

def generate_unique_filename(output_folder, base_filename):
    """既存のファイルと重複しないユニークなファイル名を生成する"""
    name, ext = os.path.splitext(base_filename)
    counter = 1
    while True:
        new_filename = f"{name}_{counter}{ext}"
        output_path = os.path.join(output_folder, new_filename)
        if not os.path.exists(output_path):
            return new_filename
        counter += 1

def process_videos(input_folder, output_folder, bgm_folder, temp_folder, output_base_filename="combined_video_with_bgm.mp4", clip_duration=3, final_duration=60, width=1080, height=1920):
    """
    指定したフォルダ内の動画ファイルをランダムに選択し、指定の長さにカットして結合し、指定の解像度にリサイズし、ランダムなBGMを追加します。
    既存のファイルがある場合は別名で保存します。
    一時ファイルは指定の一時フォルダに保存します。

    Args:
        input_folder (str): 動画ファイルが格納されたフォルダのパス.
        output_folder (str): 結合した動画を書き出すフォルダのパス.
        bgm_folder (str): BGMファイルが格納されたフォルダのパス.
        temp_folder (str): 一時ファイルを保存するフォルダのパス.
        output_base_filename (str, optional): 出力する結合動画の基本ファイル名. Defaults to "combined_video_with_bgm.mp4".
        clip_duration (int, optional): 各動画から切り出す秒数. Defaults to 3.
        final_duration (int, optional): 最終的な動画の秒数. Defaults to 60.
        width (int, optional): 出力動画の幅. Defaults to 1080.
        height (int, optional): 出力動画の高さ. Defaults to 1920.
    """
    if not os.path.exists(input_folder):
        print(f"入力フォルダ '{input_folder}' が存在しません。")
        return
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
        print(f"出力フォルダ '{output_folder}' を作成しました。")
    if not os.path.exists(bgm_folder):
        print(f"BGMフォルダ '{bgm_folder}' が存在しません。BGMは追加されません。")
        return
    if not os.path.exists(temp_folder):
        os.makedirs(temp_folder)
        print(f"一時フォルダ '{temp_folder}' を作成しました。")

    video_files = [f for f in os.listdir(input_folder) if f.endswith(('.mp4', '.avi', '.mov', '.mkv'))]
    bgm_files = [f for f in os.listdir(bgm_folder) if f.endswith(('.mp3', '.wav', '.aac'))]
    num_clips = final_duration // clip_duration

    if not video_files:
        print(f"入力フォルダ '{input_folder}' に動画ファイルが見つかりませんでした。")
        return
    if not bgm_files:
        print(f"BGMフォルダ '{bgm_folder}' にBGMファイルが見つかりませんでした。BGMは追加されません。")
        bgm_file = None
    else:
        bgm_file = os.path.join(bgm_folder, random.choice(bgm_files))

    if len(video_files) < num_clips:
        print(f"動画ファイルの数が{num_clips}個未満です。{len(video_files)}個の動画を使って可能な範囲で結合します。")
        selected_videos = random.sample(video_files, len(video_files))
    else:
        selected_videos = random.sample(video_files, num_clips)

    concat_list_path = os.path.join(temp_folder, "concat_list.txt")
    with open(concat_list_path, "w", encoding="utf-8") as f:
        for i, video_file in enumerate(selected_videos):
            input_path = os.path.join(input_folder, video_file)
            output_clip_path = os.path.join(temp_folder, f"temp_clip_{i}.mp4")
            # ffmpegで3秒にカット
            command = [
                "ffmpeg",
                "-i",
                input_path,
                "-ss",
                "0",
                "-t",
                str(clip_duration),
                "-vf",
                f"scale={width}:{height}",
                "-c:v",
                "libx264",
                "-preset",
                "ultrafast",
                "-crf",
                "23",
                "-an",  # 一時ファイルから音声トラックを削除
                output_clip_path
            ]
            try:
                result = subprocess.run(command, check=True, capture_output=True)
                f.write(f"file '{os.path.abspath(output_clip_path)}'\n")
            except subprocess.CalledProcessError as e:
                print(f"一時ファイル作成中にエラーが発生しました: {e.stderr.decode(encoding='cp932', errors='ignore')}")
                for j in range(i):
                    temp_file = os.path.join(temp_folder, f"temp_clip_{j}.mp4")
                    if os.path.exists(temp_file):
                        os.remove(temp_file)
                if os.path.exists(concat_list_path):
                    os.remove(concat_list_path)
                return

    # ffmpegで動画を結合
    intermediate_video_path = os.path.join(temp_folder, "intermediate_video.mp4")
    concat_command = [
        "ffmpeg",
        "-f",
        "concat",
        "-safe",
        "0",
        "-i",
        os.path.abspath(concat_list_path),
        "-c",
        "copy",
        intermediate_video_path
    ]
    try:
        result = subprocess.run(concat_command, check=True, capture_output=True)
    except subprocess.CalledProcessError as e:
        print(f"動画の結合中にエラーが発生しました: {e.stderr.decode(encoding='cp932', errors='ignore')}")
        if os.path.exists(concat_list_path):
            os.remove(concat_list_path)
        for i in range(len(selected_videos)):
            temp_clip_path = os.path.join(temp_folder, f"temp_clip_{i}.mp4")
            if os.path.exists(temp_clip_path):
                os.remove(temp_clip_path)
        if os.path.exists(intermediate_video_path):
            os.remove(intermediate_video_path)
        return
    finally:
        if os.path.exists(concat_list_path):
            os.remove(concat_list_path)
        for i in range(len(selected_videos)):
            temp_clip_path = os.path.join(temp_folder, f"temp_clip_{i}.mp4")
            if os.path.exists(temp_clip_path):
                os.remove(temp_clip_path)

    # BGMを追加
    output_base_path = os.path.join(output_folder, output_base_filename)
    output_filename_with_bgm = generate_unique_filename(output_folder, output_base_filename)
    output_path_with_bgm = os.path.join(output_folder, output_filename_with_bgm)

    if bgm_file:
        bgm_add_command = [
            "ffmpeg",
            "-i",
            intermediate_video_path,
            "-i",
            bgm_file,
            "-map",
            "0:v",
            "-map",
            "1:a",
            "-c:v",
            "copy",
            "-c:a",
            "aac",
            "-ac",
            "2",
            "-shortest",  # 映像が終わるタイミングで音も終わる
            output_path_with_bgm
        ]
        try:
            result = subprocess.run(bgm_add_command, check=True, capture_output=True)
            print(f"'{output_path_with_bgm}' を作成しました (BGM付き)。")
        except subprocess.CalledProcessError as e:
            print(f"BGMの追加中にエラーが発生しました: {e.stderr.decode(encoding='cp932', errors='ignore')}")
            if os.path.exists(output_path_with_bgm):
                os.remove(output_path_with_bgm)
        finally:
            if os.path.exists(intermediate_video_path):
                os.remove(intermediate_video_path)
    else:
        os.rename(intermediate_video_path, output_path_with_bgm)
        print(f"'{output_path_with_bgm}' を作成しました (BGMなし)。")

if __name__ == "__main__":
    input_folder = r"D:\python\動画制作自動化\ランダム結合\素材"
    output_folder = r"D:\python\動画制作自動化\ランダム結合\書き出し先"
    bgm_folder = r"D:\python\動画制作自動化\ランダム結合\BGM"
    temp_folder = r"D:\python\動画制作自動化\ランダム結合\一時処理"
    output_base_filename = "random_combined_with_bgm_1min.mp4"
    process_videos(input_folder, output_folder, bgm_folder, temp_folder, output_base_filename, width=1080, height=1920)

このプログラムでできること

このPythonスクリプトを実行すると、以下の処理が全自動で行われます。

  1. 指定した「素材」フォルダ (D:\python\動画制作自動化\ランダム結合\素材) 内の動画ファイルをランダムに20個選択(最終的な動画尺が1分になるように調整)。
  2. 選択した各動画の最初の3秒間を切り出し、解像度を1080×1920にリサイズ。
  3. 指定した「BGM」フォルダ (D:\python\動画制作自動化\ランダム結合\BGM) からランダムにBGMを選択し、結合した動画に自動で追加。
  4. 生成された動画は、「書き出し先」フォルダ (D:\python\動画制作自動化\ランダム結合\書き出し先) に、既存のファイルと重複しないように連番付きの別名で保存されます(例: random_combined_with_bgm_1min_1.mp4)。
  5. 一時的な処理ファイルは、「一時処理」フォルダ (D:\python\動画制作自動化\ランダム結合\一時処理) に保存され、処理後に自動で削除されます。

必要なもの

  • Python 3: プログラムの実行に必須です。
  • ffmpeg: 動画と音声の処理を行うためのコマンドラインツールです。事前にインストールし、パスを通しておく必要があります。
  • 動画ファイル: ランダムに結合したい動画素材を「素材」フォルダに格納してください。
  • BGMファイル: 動画に追加したいBGMファイル(.mp3, .wav, .aac形式など)を「BGM」フォルダに格納してください。

使い方

  1. 上記のPythonスクリプトをテキストエディタにコピーし、.py ファイルとして保存します(例: auto_bgm_shorts.py)。
  2. 指定の場所に「素材」「書き出し先」「BGM」「一時処理」の4つのフォルダを作成します。
  3. Pythonスクリプトを実行します。 Bashpython auto_bgm_shorts.py

このプログラムの魅力

  • BGM付き全自動: 動画の結合だけでなく、BGMの追加、別名保存まで完全に自動化。
  • ランダム性: 毎回異なる動画とBGMの組み合わせで、新鮮なコンテンツが生まれます。
  • 別名保存: 同じ設定で何度も実行しても、既存のファイルが上書きされる心配なし。
  • カスタマイズ可能: クリップの長さ、最終的な動画尺、解像度など、必要に応じてプログラムを柔軟に変更できます。

今後の展望

今後は、以下のような機能追加を検討しています。

  • より自然なBGMのフェードイン・フェードアウト処理
  • 動画の雰囲気に合わせたBGMの自動選択
  • テロップの自動生成機能
  • トランジション効果の自動挿入

まとめ

この全自動BGM付きショート動画作成プログラムを使えば、あなたのショート動画制作は一段と進化します。時間と手間を大幅に削減し、魅力的なコンテンツを量産して、SNSで注目を集めましょう!

注意点

  • ffmpegのインストールと環境設定が必要です。
  • 動画ファイルやBGMファイルの形式によっては、正常に処理できない場合があります。
  • プログラムの実行環境によっては、エラーが発生する可能性があります。

撮影に使用している機材【PR】

【無料】撮った写真でWEBページを作りませんか?

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
目次