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()