soiz1 commited on
Commit
ea25738
·
verified ·
1 Parent(s): d6cd3d9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -22
app.py CHANGED
@@ -7,68 +7,89 @@ import shutil
7
 
8
  def sanitize_filename(name):
9
  name = os.path.splitext(os.path.basename(name))[0]
10
- return re.sub(r'[^\w\-_.]', '_', name)
11
 
12
- def compress_video(file, resize_mode, resize_value, mute, crf_value, preset_value):
 
 
13
  if not file:
14
- return None
15
 
16
  input_path = file.name
17
  safe_name = sanitize_filename(input_path)
18
 
19
  SAVE_DIR = os.path.join(os.getcwd(), "compressed_videos")
20
  os.makedirs(SAVE_DIR, exist_ok=True)
 
21
  output_path = os.path.join(SAVE_DIR, f"{safe_name}_compressed.mp4")
22
 
23
  try:
24
  probe = ffmpeg.probe(input_path)
25
- video_stream = next((stream for stream in probe["streams"] if stream["codec_type"] == "video"), None)
26
  if not video_stream:
27
- return None
28
 
29
- width = int(video_stream["width"])
30
- height = int(video_stream["height"])
31
 
 
32
  resize_args = {}
33
  if resize_mode == "パーセンテージ":
34
  try:
35
  percent = float(resize_value.strip('%')) / 100.0
 
36
  new_width = int(width * percent)
37
  new_height = int(height * percent)
38
  resize_args = {'vf': f'scale={new_width}:{new_height}'}
39
  except Exception:
40
- return None
41
  elif resize_mode == "ピクセル指定":
42
  match = re.match(r"(\d+)[xX](\d+)", resize_value)
43
  if not match:
44
- return None
45
  new_width, new_height = map(int, match.groups())
46
  resize_args = {'vf': f'scale={new_width}:{new_height}'}
47
 
48
- audio_option = {'an': None} if mute else {'c:a': 'copy'}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
  stream = ffmpeg.input(input_path)
51
  stream = ffmpeg.output(
52
  stream,
53
  output_path,
54
- vcodec='libx264',
55
- crf=crf_value,
56
- preset=preset_value,
57
  movflags='+faststart',
58
  **resize_args,
59
- **audio_option
 
60
  )
61
  ffmpeg.run(stream, overwrite_output=True)
62
 
63
- return output_path if os.path.exists(output_path) else None
64
 
65
  except Exception as e:
66
- print(f"エラー: {e}")
67
- return None
68
 
69
 
70
  with gr.Blocks() as demo:
71
- gr.Markdown("## 🎬 高画質を維持した動画圧縮ツール (Python + FFmpeg)")
72
 
73
  with gr.Row():
74
  with gr.Column():
@@ -76,17 +97,31 @@ with gr.Blocks() as demo:
76
  resize_mode = gr.Radio(choices=["パーセンテージ", "ピクセル指定"], value="パーセンテージ", label="リサイズ方法")
77
  resize_value = gr.Textbox(label="リサイズ値(例: 80% または 1280x720)", value="100%")
78
  mute = gr.Checkbox(label="音声を消す(ミュート)", value=False)
79
- crf_value = gr.Slider(label="CRF(画質)", minimum=18, maximum=28, step=1, value=23, info="値が小さいほど高画質")
80
- preset_value = gr.Dropdown(label="エンコードプリセット", choices=["ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow"], value="slow", info="遅いほど高圧縮")
 
 
 
 
 
 
 
 
 
 
 
81
  compress_btn = gr.Button("圧縮開始")
82
 
83
  with gr.Column():
84
  result_file = gr.File(label="圧縮された動画ファイル(ダウンロード)")
 
85
 
86
  compress_btn.click(
87
  compress_video,
88
- inputs=[video_input, resize_mode, resize_value, mute, crf_value, preset_value],
89
- outputs=result_file
 
 
90
  )
91
 
92
  if __name__ == "__main__":
 
7
 
8
  def sanitize_filename(name):
9
  name = os.path.splitext(os.path.basename(name))[0]
10
+ return re.sub(r'[^一-龥\w\-_.]', '_', name)
11
 
12
+ def compress_video(file, resize_mode, resize_value, mute,
13
+ audio_codec, audio_bitrate, audio_rate, audio_channels,
14
+ video_codec, video_bitrate, framerate, pix_fmt):
15
  if not file:
16
+ return None, "ファイルが選択されていません"
17
 
18
  input_path = file.name
19
  safe_name = sanitize_filename(input_path)
20
 
21
  SAVE_DIR = os.path.join(os.getcwd(), "compressed_videos")
22
  os.makedirs(SAVE_DIR, exist_ok=True)
23
+
24
  output_path = os.path.join(SAVE_DIR, f"{safe_name}_compressed.mp4")
25
 
26
  try:
27
  probe = ffmpeg.probe(input_path)
28
+ video_stream = next((s for s in probe['streams'] if s['codec_type'] == 'video'), None)
29
  if not video_stream:
30
+ return None, "映像ストリームが見つかりません"
31
 
32
+ width = int(video_stream['width'])
33
+ height = int(video_stream['height'])
34
 
35
+ # リサイズ設定
36
  resize_args = {}
37
  if resize_mode == "パーセンテージ":
38
  try:
39
  percent = float(resize_value.strip('%')) / 100.0
40
+ assert 0 < percent <= 1
41
  new_width = int(width * percent)
42
  new_height = int(height * percent)
43
  resize_args = {'vf': f'scale={new_width}:{new_height}'}
44
  except Exception:
45
+ return None, "リサイズ値が無効です。例: 80%"
46
  elif resize_mode == "ピクセル指定":
47
  match = re.match(r"(\d+)[xX](\d+)", resize_value)
48
  if not match:
49
+ return None, "リサイズ値が無効です。例: 1280x720"
50
  new_width, new_height = map(int, match.groups())
51
  resize_args = {'vf': f'scale={new_width}:{new_height}'}
52
 
53
+ # 音声設定
54
+ if mute:
55
+ audio_args = {'an': True}
56
+ else:
57
+ audio_args = {}
58
+ if audio_codec: audio_args['c:a'] = audio_codec
59
+ if audio_bitrate: audio_args['b:a'] = audio_bitrate
60
+ if audio_rate: audio_args['ar'] = audio_rate
61
+ if audio_channels: audio_args['ac'] = audio_channels
62
+
63
+ # 映像設定
64
+ video_args = {
65
+ 'c:v': video_codec,
66
+ 'crf': 18,
67
+ 'preset': 'slow',
68
+ 'r': framerate,
69
+ 'pix_fmt': pix_fmt
70
+ }
71
+ if video_bitrate:
72
+ video_args['b:v'] = video_bitrate
73
 
74
  stream = ffmpeg.input(input_path)
75
  stream = ffmpeg.output(
76
  stream,
77
  output_path,
 
 
 
78
  movflags='+faststart',
79
  **resize_args,
80
+ **audio_args,
81
+ **video_args
82
  )
83
  ffmpeg.run(stream, overwrite_output=True)
84
 
85
+ return (output_path, None) if os.path.exists(output_path) else (None, "圧縮に失敗しました")
86
 
87
  except Exception as e:
88
+ return None, f"エラーが発生しました: {str(e)}"
 
89
 
90
 
91
  with gr.Blocks() as demo:
92
+ gr.Markdown("## 🎬 高画質を維持した動画圧縮ツール (カスタム設定付き)")
93
 
94
  with gr.Row():
95
  with gr.Column():
 
97
  resize_mode = gr.Radio(choices=["パーセンテージ", "ピクセル指定"], value="パーセンテージ", label="リサイズ方法")
98
  resize_value = gr.Textbox(label="リサイズ値(例: 80% または 1280x720)", value="100%")
99
  mute = gr.Checkbox(label="音声を消す(ミュート)", value=False)
100
+
101
+ gr.Markdown("### 音声設定")
102
+ audio_codec = gr.Textbox(label="音声コーデック (-c:a)", value="aac")
103
+ audio_bitrate = gr.Textbox(label="音声ビットレート (-b:a)", value="128k")
104
+ audio_rate = gr.Textbox(label="サンプリングレート (-ar)", value="44100")
105
+ audio_channels = gr.Textbox(label="チャンネル数 (-ac)", value="2")
106
+
107
+ gr.Markdown("### 映像設定")
108
+ video_codec = gr.Textbox(label="映像コーデック (-c:v)", value="libx264")
109
+ video_bitrate = gr.Textbox(label="映像ビットレート (-b:v、省略可)", value="")
110
+ framerate = gr.Textbox(label="フレームレート (-r)", value="30")
111
+ pix_fmt = gr.Textbox(label="ピクセルフォーマット (-pix_fmt)", value="yuv420p")
112
+
113
  compress_btn = gr.Button("圧縮開始")
114
 
115
  with gr.Column():
116
  result_file = gr.File(label="圧縮された動画ファイル(ダウンロード)")
117
+ error_output = gr.Textbox(label="エラーメッセージ", lines=2)
118
 
119
  compress_btn.click(
120
  compress_video,
121
+ inputs=[video_input, resize_mode, resize_value, mute,
122
+ audio_codec, audio_bitrate, audio_rate, audio_channels,
123
+ video_codec, video_bitrate, framerate, pix_fmt],
124
+ outputs=[result_file, error_output]
125
  )
126
 
127
  if __name__ == "__main__":