|
import os |
|
import math |
|
import shutil |
|
import gradio as gr |
|
from PIL import Image, ImageSequence |
|
from moviepy.editor import VideoFileClip |
|
|
|
TMP_DIR = "./__pycache__" |
|
|
|
|
|
def clean_cache(tmp_dir=TMP_DIR): |
|
if os.path.exists(tmp_dir): |
|
shutil.rmtree(tmp_dir) |
|
|
|
os.mkdir(tmp_dir) |
|
return f"{tmp_dir}/input.gif" |
|
|
|
|
|
def get_frame_duration(gif: Image): |
|
|
|
duration = gif.info.get("duration", 100) |
|
|
|
return [ |
|
frame.info.get("duration", duration) for frame in ImageSequence.Iterator(gif) |
|
] |
|
|
|
|
|
def resize_gif( |
|
target_width: int, |
|
target_height: int, |
|
input_path=f"{TMP_DIR}/input.gif", |
|
output_path=f"{TMP_DIR}/output.gif", |
|
): |
|
|
|
gif = Image.open(input_path) |
|
|
|
modified_frames = [] |
|
|
|
for frame in ImageSequence.Iterator(gif): |
|
|
|
resized_frame = frame.resize((target_width, target_height), Image.LANCZOS) |
|
|
|
modified_frames.append(resized_frame) |
|
|
|
frame_durations = get_frame_duration(gif) |
|
|
|
modified_frames[0].save( |
|
output_path, |
|
format="GIF", |
|
append_images=modified_frames[1:], |
|
save_all=True, |
|
duration=frame_durations, |
|
loop=0, |
|
) |
|
|
|
return output_path |
|
|
|
|
|
def infer(video_path: str, speed: float): |
|
target_w = 640 |
|
gif_path = clean_cache() |
|
try: |
|
with VideoFileClip(video_path, audio_fps=16000) as clip: |
|
if clip.duration > 5: |
|
raise ValueError("上传的视频过长 The uploaded video is too long") |
|
|
|
|
|
clip.speedx(speed).to_gif(gif_path, fps=12) |
|
w, h = clip.size |
|
|
|
target_h = math.ceil(target_w * h / w) |
|
return os.path.basename(video_path), resize_gif(target_w, target_h) |
|
|
|
except Exception as e: |
|
return f"{e}", None |
|
|
|
|
|
if __name__ == "__main__": |
|
iface = gr.Interface( |
|
fn=infer, |
|
inputs=[ |
|
gr.Video(label="上传视频 Upload video"), |
|
gr.Slider( |
|
label="倍速 Speed", |
|
minimum=0.5, |
|
maximum=2.0, |
|
step=0.25, |
|
value=1.0, |
|
), |
|
], |
|
outputs=[ |
|
gr.Textbox(label="文件名 Filename"), |
|
gr.Image(label="下载动图 Download GIF", type="filepath"), |
|
], |
|
title="请确保视频上传完整后再点击提交,若时长大于五秒可先在线裁剪<br>Please make sure the video is completely uploaded before clicking Submit, you can crop it online first if the video size is >5s", |
|
allow_flagging="never", |
|
) |
|
|
|
iface.launch() |
|
|