-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathextractor.py
More file actions
150 lines (120 loc) · 4.7 KB
/
Copy pathextractor.py
File metadata and controls
150 lines (120 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import argparse
import shutil
import subprocess
import sys
from pathlib import Path
SUPPORTED_EXTENSIONS = {".mov", ".mp4", ".avi", ".mkv", ".m4v", ".mts", ".ts"}
def ensure_ffmpeg():
"""ffmpegがPATHに無ければwingetで自動インストールする"""
if shutil.which("ffmpeg") is not None:
return
print("ffmpeg が見つかりません。winget でインストールを試みます...")
if shutil.which("winget") is None:
print("エラー: winget が見つかりません。")
print("手動でインストールしてください: https://ffmpeg.org/download.html")
sys.exit(1)
install_cmd = [
"winget", "install",
"--id", "Gyan.FFmpeg",
"-e",
"--accept-source-agreements",
"--accept-package-agreements",
]
result = subprocess.run(install_cmd)
if result.returncode != 0:
print("エラー: winget によるインストールに失敗しました。")
print("手動でインストールしてください: winget install ffmpeg")
sys.exit(1)
print("\nインストール完了。")
print("注意: 新しいPowerShellウィンドウで再実行する必要がある場合があります")
print("(PATHの反映に再起動が必要なため)。\n")
if shutil.which("ffmpeg") is None:
print("インストールされましたが、現在のセッションではまだ認識されません。")
print("PowerShellを開き直してから再実行してください。")
sys.exit(1)
def extract_frames(
input_path: str,
output_dir: str,
fps: float = None,
start_time: float = None,
end_time: float = None,
quality: int = 2,
prefix: str = "frame",
width: int = None,
height: int = None,
):
input_path = Path(input_path)
output_dir = Path(output_dir)
output_dir.mkdir(parents=True, exist_ok=True)
if not input_path.exists():
print(f"エラー: ファイルが見つかりません: {input_path}")
sys.exit(1)
ext = input_path.suffix.lower()
if ext not in SUPPORTED_EXTENSIONS:
supported = ", ".join(sorted(SUPPORTED_EXTENSIONS))
print(f"エラー: 非対応のフォーマットです: {ext}")
print(f"対応フォーマット: {supported}")
sys.exit(1)
cmd = ["ffmpeg", "-y"]
if start_time is not None:
cmd += ["-ss", str(start_time)]
cmd += ["-i", str(input_path)]
if end_time is not None:
if start_time:
cmd += ["-t", str(end_time - start_time)]
else:
cmd += ["-to", str(end_time)]
filters = []
if fps is not None:
filters.append(f"fps={fps}")
if width or height:
w = str(width) if width else "-1"
h = str(height) if height else "-1"
filters.append(f"scale={w}:{h}")
if filters:
cmd += ["-vf", ",".join(filters)]
cmd += [
"-q:v", str(quality),
str(output_dir / f"{prefix}_%05d.jpg"),
]
print(f"入力: {input_path.name} ({ext})")
print(f"出力: {output_dir}")
print(f"実行: {' '.join(cmd)}\n")
result = subprocess.run(cmd, stderr=subprocess.PIPE, text=True)
if result.returncode != 0:
print("ffmpeg エラー:")
print(result.stderr)
sys.exit(1)
frames = list(output_dir.glob(f"{prefix}_*.jpg"))
print(f"\n完了: {len(frames)} 枚を保存しました")
return frames
def main():
exts = " / ".join(sorted(SUPPORTED_EXTENSIONS))
p = argparse.ArgumentParser(
description=f"動画から JPEG フレームを切り出す ({exts})"
)
p.add_argument("input", help="入力動画ファイル")
p.add_argument("output_dir", help="出力ディレクトリ")
p.add_argument("--fps", type=float, help="フレームレート (例: 20 = 50ms間隔)")
p.add_argument("--start", type=float, help="開始秒")
p.add_argument("--end", type=float, help="終了秒")
p.add_argument("--quality", "-q", type=int, default=2,
help="JPEG品質 1(最高)~31(最低) [デフォルト: 2]")
p.add_argument("--prefix", default="frame", help="ファイル名プレフィックス")
p.add_argument("--width", "-W", type=int, help="リサイズ幅 (px)")
p.add_argument("--height", "-H", type=int, help="リサイズ高さ (px)")
args = p.parse_args()
ensure_ffmpeg()
extract_frames(
input_path=args.input,
output_dir=args.output_dir,
fps=args.fps,
start_time=args.start,
end_time=args.end,
quality=args.quality,
prefix=args.prefix,
width=args.width,
height=args.height,
)
if __name__ == "__main__":
main()