File size: 3,137 Bytes
70d9bc3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227dd7c
 
 
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
import gradio as gr
import tempfile
import os
import subprocess
from imageio_ffmpeg import get_ffmpeg_exe


def rotate_video(input_file, rotation):
    if not input_file:
        return None, None
    angles = {
        "90° clockwise": -90,
        "90° counter-clockwise": 90,
        "180°": 180,
    }
    angle = angles.get(rotation, -90)
    # Resolve input path from various possible formats (str path, dict with path/name, or file-like)
    input_path = None
    if isinstance(input_file, str) and os.path.exists(input_file):
        input_path = input_file
    elif isinstance(input_file, dict):
        # Try common keys first
        for k in ("path", "name", "video", "file"):
            v = input_file.get(k)
            if isinstance(v, str) and os.path.exists(v):
                input_path = v
                break
        # Fallback: scan all values for a valid path string
        if not input_path:
            for v in input_file.values():
                if isinstance(v, str) and os.path.exists(v):
                    input_path = v
                    break
    elif hasattr(input_file, "name"):
        v = getattr(input_file, "name", None)
        if v and os.path.exists(v):
            input_path = v
    if not input_path:
        return None, None
    tmpdir = tempfile.mkdtemp(prefix="rotate_")
    out_path = os.path.join(tmpdir, "rotated.mp4")

    # Build FFmpeg transpose filter (no borders for multiples of 90)
    if angle == -90:  # clockwise
        vf_filter = "transpose=1"
    elif angle == 90:  # counter-clockwise
        vf_filter = "transpose=2"
    elif angle == 180 or angle == -180:
        vf_filter = "transpose=1,transpose=1"  # 180°
    else:
        vf_filter = "transpose=1"  # default safeguard

    ffmpeg_exe = get_ffmpeg_exe()
    base_cmd = [
        ffmpeg_exe,
        "-y",
        "-i", input_path,
        "-vf", vf_filter,
        "-c:v", "libx264",
        "-pix_fmt", "yuv420p",
        "-preset", "medium",
        "-crf", "20",
        "-movflags", "+faststart",
        "-c:a", "aac",
        out_path,
    ]
    try:
        subprocess.run(base_cmd, check=True)
    except subprocess.CalledProcessError:
        # Fallback: try without audio if AAC not available
        cmd_no_audio = base_cmd.copy()
        # replace audio settings with -an
        if "-c:a" in cmd_no_audio:
            idx = cmd_no_audio.index("-c:a")
            # remove -c:a and its value
            del cmd_no_audio[idx:idx+2]
        cmd_no_audio.insert(-1, "-an")
        subprocess.run(cmd_no_audio, check=True)
    return out_path, out_path


with gr.Blocks() as demo:
    gr.Markdown("# Video Rotate")
    with gr.Row():
        input_video = gr.Video(label="Input") 
        rotation = gr.Radio(choices=["90° clockwise", "90° counter-clockwise", "180°"], value="90° counter-clockwise", label="Rotation")
    out_preview = gr.Video(label="Preview")
    out_file = gr.File(label="Download MP4")
    run_btn = gr.Button("Rotate")
    run_btn.click(rotate_video, inputs=[input_video, rotation], outputs=[out_preview, out_file])


if __name__ == "__main__":
    demo.launch()