Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import ffmpeg | |
| import os | |
| import tempfile | |
| import re | |
| import shutil | |
| def sanitize_filename(name): | |
| name = os.path.splitext(os.path.basename(name))[0] | |
| return re.sub(r'[^一-龥\w\-_.]', '_', name) | |
| def compress_video(file, resize_mode, resize_value, mute, | |
| audio_codec, audio_bitrate, audio_rate, audio_channels, | |
| video_codec, video_bitrate, framerate, pix_fmt): | |
| if not file: | |
| return None, "ファイルが選択されていません" | |
| input_path = file.name | |
| safe_name = sanitize_filename(input_path) | |
| SAVE_DIR = os.path.join(os.getcwd(), "compressed_videos") | |
| os.makedirs(SAVE_DIR, exist_ok=True) | |
| output_path = os.path.join(SAVE_DIR, f"{safe_name}_compressed.mp4") | |
| try: | |
| probe = ffmpeg.probe(input_path) | |
| video_stream = next((s for s in probe['streams'] if s['codec_type'] == 'video'), None) | |
| if not video_stream: | |
| return None, "映像ストリームが見つかりません" | |
| width = int(video_stream['width']) | |
| height = int(video_stream['height']) | |
| # リサイズ設定 | |
| resize_args = {} | |
| if resize_mode == "パーセンテージ": | |
| try: | |
| percent = float(resize_value.strip('%')) / 100.0 | |
| assert 0 < percent <= 1 | |
| new_width = int(width * percent) | |
| new_height = int(height * percent) | |
| resize_args = {'vf': f'scale={new_width}:{new_height}'} | |
| except Exception: | |
| return None, "リサイズ値が無効です。例: 80%" | |
| elif resize_mode == "ピクセル指定": | |
| match = re.match(r"(\d+)[xX](\d+)", resize_value) | |
| if not match: | |
| return None, "リサイズ値が無効です。例: 1280x720" | |
| new_width, new_height = map(int, match.groups()) | |
| resize_args = {'vf': f'scale={new_width}:{new_height}'} | |
| # 音声設定 | |
| if mute: | |
| audio_args = {'an': True} | |
| else: | |
| audio_args = {} | |
| if audio_codec: audio_args['c:a'] = audio_codec | |
| if audio_bitrate: audio_args['b:a'] = audio_bitrate | |
| if audio_rate: audio_args['ar'] = audio_rate | |
| if audio_channels: audio_args['ac'] = audio_channels | |
| # 映像設定 | |
| video_args = { | |
| 'c:v': video_codec, | |
| 'crf': 18, | |
| 'preset': 'slow', | |
| 'r': framerate, | |
| 'pix_fmt': pix_fmt | |
| } | |
| if video_bitrate: | |
| video_args['b:v'] = video_bitrate | |
| stream = ffmpeg.input(input_path) | |
| stream = ffmpeg.output( | |
| stream, | |
| output_path, | |
| movflags='+faststart', | |
| **resize_args, | |
| **audio_args, | |
| **video_args | |
| ) | |
| ffmpeg.run(stream, overwrite_output=True) | |
| return (output_path, None) if os.path.exists(output_path) else (None, "圧縮に失敗しました") | |
| except Exception as e: | |
| return None, f"エラーが発生しました: {str(e)}" | |
| with gr.Blocks() as demo: | |
| gr.Markdown("## 🎬 高画質を維持した動画圧縮ツール (カスタム設定付き)") | |
| with gr.Row(): | |
| with gr.Column(): | |
| video_input = gr.File(label="動画ファイルを選択", file_types=[".mp4", ".mov", ".mkv", ".avi"]) | |
| resize_mode = gr.Radio(choices=["パーセンテージ", "ピクセル指定"], value="パーセンテージ", label="リサイズ方法") | |
| resize_value = gr.Textbox(label="リサイズ値(例: 80% または 1280x720)", value="100%") | |
| mute = gr.Checkbox(label="音声を消す(ミュート)", value=False) | |
| gr.Markdown("### 音声設定") | |
| audio_codec = gr.Textbox(label="音声コーデック (-c:a)", value="aac") | |
| audio_bitrate = gr.Textbox(label="音声ビットレート (-b:a)", value="128k") | |
| audio_rate = gr.Textbox(label="サンプリングレート (-ar)", value="44100") | |
| audio_channels = gr.Textbox(label="チャンネル数 (-ac)", value="2") | |
| gr.Markdown("### 映像設定") | |
| video_codec = gr.Textbox(label="映像コーデック (-c:v)", value="libx264") | |
| video_bitrate = gr.Textbox(label="映像ビットレート (-b:v、省略可)", value="") | |
| framerate = gr.Textbox(label="フレームレート (-r)", value="30") | |
| pix_fmt = gr.Textbox(label="ピクセルフォーマット (-pix_fmt)", value="yuv420p") | |
| compress_btn = gr.Button("圧縮開始") | |
| with gr.Column(): | |
| result_file = gr.File(label="圧縮された動画ファイル(ダウンロード)") | |
| error_output = gr.Textbox(label="エラーメッセージ", lines=2) | |
| compress_btn.click( | |
| compress_video, | |
| inputs=[video_input, resize_mode, resize_value, mute, | |
| audio_codec, audio_bitrate, audio_rate, audio_channels, | |
| video_codec, video_bitrate, framerate, pix_fmt], | |
| outputs=[result_file, error_output] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |