.TSファイルを.mp4に変換するPython scriptをgemini3と一緒に作ってみた

私のPCの環境はお世辞にも新しいと言えないのです。

CPU:Intel i9-9900es GPU:GEFORCE GTX1060 6GB 2枚搭載という環境です。OSはWindows11pro 25H2

CPUもGPUもヤフオクで購入です。GPUに至っては、ヤフオクで中古で購入でした。

今回は、拡張子tsのファイルを1920*1080のFHD、ファイルサイズは500MB以下に自動的に圧縮して保存するPythonコードをgemini3にお願いして作ってみました。

前提条件

前提条件:

「FFmpegがインストールされ、パスが通っていること」

「NVIDIAのGPU(およびドライバ)がインストールされていること」

カスタマイズ:

target_size_mb = 500 の数値を変えれば、好みのサイズに調整できます。←1ファイルの上限を500MB以下としています。

NvidiaのGPUを使っているならそのままコピーで試してみて

先にAMD用に変更する部分のコードを記載しておきます。ただし、当方で動作環境がないので未確認です。

# --- AMD GPU (AMF) 用のコマンド設定 ---
final_cmd = [
    'ffmpeg', '-y', '-i', input_path,
    '-c:v', 'h264_amf',              # AMDのエンコーダーを指定
    '-b:v', f'{video_bitrate}k',     # 映像ビットレート
    '-s', '1920x1080',               # フルHD
    '-quality', 'quality',           # 画質優先設定(speed, balanced, quality)
    '-rc', 'vbr_peak',               # 可変ビットレート制御
    '-c:a', 'aac', '-b:a', '128k',
    output_path
]

コード本体はこちらになります。こちらは動作検証済みです。

import os
import subprocess
import tkinter as tk
from tkinter import filedialog

def get_duration(input_file):
    """動画の長さを取得する"""
    cmd = [
        'ffprobe', '-v', 'error', 
        '-show_entries', 'format=duration', 
        '-of', 'default=noprint_wrappers=1:nokey=1', 
        input_file
    ]
    result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding='utf-8')
    if result.returncode != 0:
        return None
    return float(result.stdout.strip())

def get_best_gpu():
    """空いているGPUを選択"""
    try:
        cmd = "nvidia-smi --query-gpu=utilization.gpu --format=csv,nounits,noheader"
        result = subprocess.check_output(cmd, shell=True).decode('utf-8')
        utils = [int(x) for x in result.strip().split('\n')]
        return utils.index(min(utils))
    except:
        return 0

def main():
    # 1. ファイル選択ダイアログを表示(複数選択を許可)
    root = tk.Tk()
    root.withdraw()
    print("変換したいTSファイルをすべて選択してください(Ctrlキーやマウスドラッグで複数選べます)...")
    
    # askopenfilenames (最後にsがつく) に変更
    file_paths = filedialog.askopenfilenames(title="TSファイルを複数選択してください", filetypes=[("TS files", "*.ts")])
    
    if not file_paths:
        print("ファイルが選択されませんでした。")
        return

    total_files = len(file_paths)
    print(f"{total_files} 個のファイルが選択されました。変換を開始します。\n")

    for i, raw_path in enumerate(file_paths, 1):
        input_path = os.path.normpath(raw_path)
        output_path = os.path.splitext(input_path)[0] + ".mp4"
        
        filename = os.path.basename(input_path)
        print(f"[{i}/{total_files}] 処理中: {filename}")

        # 2. 動画の長さを取得
        duration = get_duration(input_path)
        if duration is None:
            print(f"   × エラー: {filename} の長さが取得できません。スキップします。")
            continue

        # 3. ビットレート計算 (500MB目安)
        target_size_mb = 500
        target_total_bitrate = (target_size_mb * 8192 * 0.94) / duration
        video_bitrate = int(target_total_bitrate - 128)

        # 4. GPU選択(ファイルごとに空いている方を確認)
        selected_gpu = get_best_gpu()
        
        final_cmd = [
            'ffmpeg', '-y', '-i', input_path,
            '-c:v', 'h264_nvenc', '-b:v', f'{video_bitrate}k',
            '-maxrate', f'{video_bitrate * 2}k', '-bufsize', f'{video_bitrate * 2}k',
            '-gpu', str(selected_gpu), '-s', '1920x1080',
            '-c:a', 'aac', '-b:a', '128k',
            output_path
        ]

        try:
            # 実行
            subprocess.run(final_cmd, check=True, capture_output=True)
            print(f"   ○ 完了!")
        except subprocess.CalledProcessError as e:
            print(f"   × 変換エラー: {e}")

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

if __name__ == "__main__":
    main()

geminiに転載の許可は取ってあります。(笑)

タイトルとURLをコピーしました