本ページはプロモーションが含まれています。
ffmpegで動画を毎晩変換するバッチを書いたものの、共有レンタルサーバーでは途中で止まる、手元のPCでは朝まで起動しておけない。そんな悩みを持つ方に向けて、ffmpeg 7.1をPythonから呼び出す「今の書き方」と、毎晩変換する処理の置き場所の選び方をまとめました。比較するのはエックスサーバー、ConoHa VPS、自宅機の3つです。2026年11月時点の料金、cronの可否、root権限、それぞれが止まる条件を並べます。自分の素材でCPU負荷を測る手順も載せているので、その結果をもとに選べます。
ffmpeg 7.1の夜間変換バッチ:subprocessで呼ぶ今の書き方
実行環境と準備するもの
- Python:3.9以降を前提にしています。
list[str]という型ヒントの書き方を使うためです。確認はpython3 --versionで行います。 - pip install するパッケージ:ありません。標準ライブラリ(subprocess・pathlib・logging)だけで書いています。
- ffmpeg:本記事は7.1を想定しています。OSのパッケージで入るバージョンは環境ごとに違うので、
ffmpeg -versionの1行目で確認してください。下のコードで使うエンコーダーとオプションが手元で使えるかは、ffmpeg -h encoder=libx264や公式ドキュメントで確かめられます。
以前の書き方と、今の書き方
項目 | 以前の書き方 | 今の書き方 |
|---|---|---|
ffmpegの呼び出し |
|
|
止まらない処理への対策 | 何もしない(固まると翌晩の分と重なる) |
|
出力ファイル | 最終ファイル名へ直接書き込む(途中で落ちると壊れたMP4が残る) |
|
CPUの使い方 | そのまま全力で回す |
|
結果の記録 | 標準出力を捨てる | 1本ごとの所要時間と失敗理由をログに残す。置き場所を決める材料にもなる |
コード全体(convert.py)
#!/usr/bin/env python3
"""inbox の動画を毎晩まとめて H.264/AAC の MP4 に変換する"""
import logging
import shutil
import subprocess
import sys
import time
from pathlib import Path
BASE = Path("/home/username/videos")
SRC = BASE / "inbox"
DST = BASE / "converted"
DONE = BASE / "done"
LOG = BASE / "logs" / "convert.log"
EXTS = {".mov", ".mp4", ".mkv"}
TIMEOUT_SEC = 60 * 60 # 1本あたりの上限
SETTLE_SEC = 5 * 60 # 更新から5分たっていないファイルはアップロード中とみなす
def build_cmd(src: Path, out: Path) -> list[str]:
return [
"nice", "-n", "19",
"ffmpeg", "-hide_banner", "-nostdin", "-loglevel", "error", "-y",
"-i", str(src),
"-c:v", "libx264", "-preset", "medium", "-crf", "23",
"-c:a", "aac", "-b:a", "128k",
"-movflags", "+faststart",
"-f", "mp4", str(out),
]
def convert_one(src: Path) -> bool:
dst = DST / (src.stem + ".mp4")
part = DST / (src.stem + ".mp4.part")
started = time.monotonic()
try:
result = subprocess.run(
build_cmd(src, part),
capture_output=True, text=True, errors="replace",
timeout=TIMEOUT_SEC,
)
except subprocess.TimeoutExpired:
part.unlink(missing_ok=True)
logging.error("timeout: %s", src.name)
return False
elapsed = time.monotonic() - started
if result.returncode != 0:
part.unlink(missing_ok=True)
logging.error("failed: %s\n%s", src.name, result.stderr[-2000:])
return False
part.rename(dst)
shutil.move(str(src), DONE / src.name)
logging.info("ok: %s %.1fs", src.name, elapsed)
return True
def main() -> int:
for d in (DST, DONE, LOG.parent):
d.mkdir(parents=True, exist_ok=True)
logging.basicConfig(filename=LOG, level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s")
if shutil.which("ffmpeg") is None:
logging.error("ffmpeg not found in PATH")
return 1
now = time.time()
targets = [p for p in sorted(SRC.iterdir())
if p.suffix.lower() in EXTS and now - p.stat().st_mtime > SETTLE_SEC]
failed = 0
for src in targets:
if not convert_one(src):
failed += 1
logging.info("done: %d files, %d failed", len(targets), failed)
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(main())
ブロックごとの説明
- 定数部分:入力(inbox)、出力(converted)、処理済みの退避先(done)、ログの場所を
/home/username/videosの下にまとめています。SETTLE_SECは、アップロード中のファイルを変換し始めないための待ち時間です。 - build_cmd():ffmpegの引数をリストで組み立てます。
nice -n 19はOSに「この処理の優先度は最低でよい」と伝えるコマンドです。-nostdinはcronのような端末のない環境で入力待ちにならないように、-loglevel errorはエラー以外を出さずログを小さく保つために付けています。画質は-crf(値が小さいほど高画質で大きいファイル)、速度は-presetで調整します。 - convert_one():1本を変換します。出力先は
.partなので、拡張子からは形式を判断できません。そのため-f mp4で形式を明示しています。成功したらリネームし、元ファイルはdoneへ移します。こうしておくと、翌晩に同じファイルをもう一度変換することがありません。時間切れや失敗のときは中途半端な.partを消し、ffmpegのエラー出力の末尾をログに残します。 - main():フォルダを用意し、ffmpegがPATH(コマンドを探す場所の一覧)にあるかを先に確かめます。cronはログイン時と違う最小限のPATHで動くため、ここで止まる例が多いからです。失敗が1本でもあれば終了コード1を返します。cron側やGitHub Actions側で異常を検知しやすくするためです。
CPU負荷と処理時間を自分の素材で測る(/usr/bin/timeとログ)
動画変換の重さは、素材の長さ・解像度・-presetの値で大きく変わります。他人の実測値はそのまま当てはまりません。私は置き場所を決める前に、まず1晩分の素材を手元で変換して、次の項目を測るようにしています。
測り方
/usr/bin/time -v python3 /home/username/videos/convert.py
grep "ok:" /home/username/videos/logs/convert.log
nproc
free -h
測る項目 | 確認方法 | 判断に使うこと |
|---|---|---|
1晩分の合計時間 |
| 夜間のうちに終わるか。1vCPUのVPSでも足りるか |
1本あたりの所要時間 | ログの |
|
最大メモリ使用量 |
| メモリ512MB〜1GBのプランで足りるか |
測った機械のコア数 |
| コア数の違うVPSで時間がどう変わるかの見積もり |
測った機械がVPSより多くのコアを持っていれば、VPSではその分だけ遅くなると見込んでおくのが無難です。最終的には、後述する時間課金・無料お試しのVPSで同じスクリプトを1回流して確かめるのが確実です。
エックスサーバー・ConoHa VPS・自宅機の比較(2026年11月の料金とCPU制限)
比較表
置き場所 | 2026年11月時点の料金 | cron | 常駐 | root権限 | CPU |
|---|---|---|---|---|---|
エックスサーバー(スタンダード) | 月額1,100円〜(12ヶ月契約)、10日間無料お試し | 可(最短5分間隔) | 原則不可 | 不可 | 共用 |
ConoHa VPS(最安プラン) | 1ヶ月契約で月額460円、36ヶ月一括で月額換算326円、時間課金あり | 可(最短1分) | 可 | 可 | 1コア |
シンVPS 4GB | 36ヶ月契約で月額1,350円(3ヶ月契約は月額1,771円) | 可(最短1分) | 可 | 可 | プラン依存 |
XServer VPS クラウド 4GB | 月額2,480円(2026年8月31日開始、自動バックアップ付き) | 可 | 可 | 可 | プラン依存 |
自宅機 | 機械と電気代のみ | 可 | 可 | 可 | 手持ちの機械次第 |
- ConoHa VPSの最安プランのメモリは、調査の段階で1GBとする情報と512MBとする情報がありました。契約前に公式の料金ページで確認してください。
- Xserver VPSは2026年9月17日から全プランの新規受付を一時停止しています。2026年11月中に再開する予定ですが、確定ではありません。停止前の4GBプラン(4コア・4GB・150GB NVMe SSD)は、1ヶ月契約で月額2,640円でした。
- さくらのVPSは石狩リージョンの1GBが月額880円で、2週間の無料お試しがあります。CVE-2026-99999への対応で止まっていた新規申し込みも、11月10日までに大阪リージョンのLinux通常容量プランを除いて再開しています。
共有レンタルサーバーで変換を回しにくい理由
エックスサーバーのような共有レンタルサーバーでもcronは使えます。ただし、CPU重めの変換を毎晩回すには、次の点で詰まりやすくなります。
- root権限がない:OSのパッケージとしてffmpegを入れられません。自前のバイナリを置くことが規約上許されるかは、事業者のマニュアルで確認が必要です。
- CPU・メモリが共用:他の利用者と同じ機械を分け合っています。長時間CPUを使い切る処理は、負荷が高いとして止められる可能性があります。具体的な制限値は公式マニュアルで確認してください。
- 常駐が原則不可で、プロセスにタイムアウトがある:1本に数十分かかる変換は途中で終了させられることがあります。この症状と、処理を分割して逃がす書き方はレンタルサーバー cron 強制終了|30分バッチ 26年11月にまとめています。
Webサイトの置き場所としては、2026年10月のPHP脆弱性(PHP2shell)の際、エックスサーバーは翌朝には対応作業を始めていたという評価があります。サイトは共有サーバーに置き、重い変換だけをVPSか自宅機に分ける構成が現実的です。
条件別の選び方と、それぞれが止まる条件
あなたの条件 | 選ぶ置き場所 | 止まる条件 |
|---|---|---|
測った処理が1本数分で終わり、追加ソフトが要らない | 共有レンタルサーバーのcron(ただしffmpegが使える場合に限る) | 実行時間・CPUの制限に当たったとき、ffmpegを置けないとき、規約上重い処理と判断されたとき |
1晩の合計が長く、最大メモリが1GBに収まる | ConoHa VPSなどの1GB級VPS(時間課金で試してから月額・長期契約へ) | メモリ不足でプロセスが落ちたとき、カーネル更新などのメンテナンスで再起動したとき、支払いが止まったとき、SSHを開けっぱなしにして侵入されたとき |
4K素材などでメモリやコアが足りない | シンVPS 4GBやXServer VPS クラウドなど4GB級のVPS | 上と同じ。加えて、新規受付の停止中(Xserver VPS)は契約できない |
素材が自宅にあり、手元に高性能な機械がある | 自宅機のcron(外部に公開しない) | スリープ・電源断・OS更新による再起動、家族による電源オフ、機械の故障 |
素材を毎晩数GB単位で上げ下ろしするなら、アップロードの手間と回線の負担も考えてください。自宅に素材がある場合は、自宅機で変換して完成品だけをサーバーへ送る方が速いことも多いです。
毎晩動かし続ける設定:cron・flock・VPSの最低限の防御
cronの設定
30 1 * * * /usr/bin/flock -n /home/username/videos/convert.lock /usr/bin/python3 /home/username/videos/convert.py >> /home/username/videos/logs/cron.log 2>&1
30 1 * * *:毎日1時30分に起動します。flock -n:ロックファイルを使って、前の晩の変換がまだ動いていれば今夜の起動をすぐ諦めます。2本同時にffmpegが走ってCPUを取り合うのを防ぐ仕組みです。- コマンドはフルパスで書きます。cronのPATHは最小限なので、
python3だけでは見つからないことがあるためです。 - 失敗に気づける仕組みも必要です。cronの出力をメールで受け取る方法と、VPSで25番ポートが塞がれている場合の考え方はcron メール通知 置き場所|25番ポートと26年11月料金で扱っています。
小さなVPSでも開設直後から狙われる
「変換するだけの無名サーバーだから」という油断は通用しません。ConoHa VPSのCPU1コア・メモリ512MBの小型サーバーでは、開設直後から世界各地から3万回を超える不審な接続があったと報告されています。わずか16秒でプログラムの持ち込み・起動・削除まで試みる攻撃も観測されました(2026年10月21日〜29日の観測)。また、2026年10月16日にはLinuxカーネルの脆弱性CVE-2026-99999(通称PwnEscape)が公開され、VPS各社が対応に追われました。VPSを選んだら、最初に次の作業を済ませてください。
- SSHは鍵認証にし、
/etc/ssh/sshd_configでPasswordAuthentication noにする(接続はssh username@203.0.113.10のように鍵で行う) - ファイアウォールで、使うポート以外を閉じる。変換バッチだけならWebのポートを開ける必要はない
- OSとカーネルの更新を定期的に当て、再起動後にcronが動いているかをログで確認する
自宅機は、外部から接続できるように公開しなければ、こうした攻撃の対象になりにくくなります。素材の受け渡しのためだけにポートを開けるのは避けましょう。
素材の取得元への配慮(robots.txt・利用規約・アクセス間隔)
変換する動画を自分の機材やストレージから集めるなら問題ありません。外部のサイトから素材を取得して変換する場合は、次の点を守ってください。
- robots.txt(クローラーに取得してよい範囲を伝えるファイル)を
https://example.com/robots.txtのように確認し、禁止されているパスは取得しない - 利用規約で自動取得・ダウンロード・再加工が許されているかを確認する。動画は著作物なので、規約で許されていても変換後の公開範囲には注意する
- アクセス間隔:1ファイルごとに
time.sleep()で十分な間隔をあけ、並列で一斉に取得しない。動画は1ファイルが大きいため、相手の回線への負担は普通のページ取得より重くなる - ログインや取得制限がかかっている素材を、仕組みを回避して取りに行かない。権限のある方法(提供元のエクスポート機能や公式APIなど)がある場合はそちらを使う
関連する選択肢
毎日決まった時刻にスクリプトを動かすだけなら、共有のレンタルサーバーでも足ります。cronが使えるプランを選べば、自分でOSを管理する必要はありません。
※ 広告を含みます(A8.net)。リンク経由でお申し込みがあった場合、手数料を受け取ることがあります。
まとめ:毎晩の変換を止めないための3つの判断
ffmpegの夜間バッチは、subprocess.run()にリストで引数を渡し、timeout・.part出力・nice・flockを組み合わせるのが今の書き方です。置き場所は、まず自分の素材で合計時間と最大メモリを測ってから決めます。エックスサーバーのような共有サーバーはcronこそ最短5分間隔で使えますが、root権限がなく常駐も原則不可なので、重い変換には向きません。1GBに収まるならConoHa VPS(月額460円〜)、足りなければシンVPS 4GB(36ヶ月契約で月額1,350円)などの4GB級、素材が手元にあるなら自宅機が候補です。VPSは開設直後から攻撃されるため、鍵認証・ファイアウォール・更新の3点を最初に済ませてください。