File size: 5,152 Bytes
7c204f4
 
 
 
 
73f6066
 
 
 
ea25738
7c204f4
ea25738
 
 
7c204f4
ea25738
7c204f4
 
73f6066
7c204f4
73f6066
 
ea25738
73f6066
7c204f4
 
73f6066
ea25738
73f6066
ea25738
73f6066
ea25738
 
73f6066
ea25738
73f6066
 
 
 
ea25738
73f6066
 
 
 
ea25738
73f6066
 
 
ea25738
73f6066
 
 
ea25738
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73f6066
7c204f4
 
 
 
73f6066
7c204f4
ea25738
 
7c204f4
 
 
ea25738
73f6066
 
ea25738
7c204f4
 
 
ea25738
73f6066
7c204f4
 
73f6066
7c204f4
 
 
ea25738
 
 
 
 
 
 
 
 
 
 
 
 
73f6066
 
7c204f4
73f6066
ea25738
7c204f4
 
 
ea25738
 
 
 
7c204f4
 
 
 
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
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()