Spaces:
Running
Running
Upload 2 files
Browse files- app.py +99 -0
- requirements.txt +2 -0
app.py
ADDED
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import math
|
3 |
+
import shutil
|
4 |
+
import gradio as gr
|
5 |
+
from PIL import Image, ImageSequence
|
6 |
+
from moviepy.editor import VideoFileClip
|
7 |
+
|
8 |
+
TMP_DIR = "./__pycache__"
|
9 |
+
|
10 |
+
|
11 |
+
def clean_cache(tmp_dir=TMP_DIR):
|
12 |
+
if os.path.exists(tmp_dir):
|
13 |
+
shutil.rmtree(tmp_dir)
|
14 |
+
|
15 |
+
os.mkdir(tmp_dir)
|
16 |
+
return f"{tmp_dir}/input.gif"
|
17 |
+
|
18 |
+
|
19 |
+
def get_frame_duration(gif: Image):
|
20 |
+
# 获取 GIF 图像中第一帧的 duration
|
21 |
+
duration = gif.info.get("duration", 100)
|
22 |
+
# 返回每一帧的 duration
|
23 |
+
return [
|
24 |
+
frame.info.get("duration", duration) for frame in ImageSequence.Iterator(gif)
|
25 |
+
]
|
26 |
+
|
27 |
+
|
28 |
+
def resize_gif(
|
29 |
+
target_width: int,
|
30 |
+
target_height: int,
|
31 |
+
input_path=f"{TMP_DIR}/input.gif",
|
32 |
+
output_path=f"{TMP_DIR}/output.gif",
|
33 |
+
):
|
34 |
+
# Open the GIF image
|
35 |
+
gif = Image.open(input_path)
|
36 |
+
# Create a list to hold the modified frames
|
37 |
+
modified_frames = []
|
38 |
+
# Loop through each frame of the GIF
|
39 |
+
for frame in ImageSequence.Iterator(gif):
|
40 |
+
# Resize the frame
|
41 |
+
resized_frame = frame.resize((target_width, target_height), Image.LANCZOS)
|
42 |
+
# Append the resized frame to the list
|
43 |
+
modified_frames.append(resized_frame)
|
44 |
+
|
45 |
+
frame_durations = get_frame_duration(gif)
|
46 |
+
# 将修改后的帧作为新的 GIF 保存
|
47 |
+
modified_frames[0].save(
|
48 |
+
output_path,
|
49 |
+
format="GIF",
|
50 |
+
append_images=modified_frames[1:],
|
51 |
+
save_all=True,
|
52 |
+
duration=frame_durations,
|
53 |
+
loop=0,
|
54 |
+
)
|
55 |
+
|
56 |
+
return output_path
|
57 |
+
|
58 |
+
|
59 |
+
def infer(video_path: str, speed: float):
|
60 |
+
target_w = 640
|
61 |
+
gif_path = clean_cache()
|
62 |
+
try:
|
63 |
+
with VideoFileClip(video_path, audio_fps=16000) as clip:
|
64 |
+
if clip.duration > 5:
|
65 |
+
raise ValueError("上传的视频过长 The uploaded video is too long")
|
66 |
+
|
67 |
+
# clip.write_gif(gif_path, fps=12, progress_bar=True)
|
68 |
+
clip.speedx(speed).to_gif(gif_path, fps=12)
|
69 |
+
w, h = clip.size
|
70 |
+
|
71 |
+
target_h = math.ceil(target_w * h / w)
|
72 |
+
return os.path.basename(video_path), resize_gif(target_w, target_h)
|
73 |
+
|
74 |
+
except Exception as e:
|
75 |
+
return f"{e}", None
|
76 |
+
|
77 |
+
|
78 |
+
if __name__ == "__main__":
|
79 |
+
iface = gr.Interface(
|
80 |
+
fn=infer,
|
81 |
+
inputs=[
|
82 |
+
gr.Video(label="上传视频 Upload video"),
|
83 |
+
gr.Slider(
|
84 |
+
label="倍速 Speed",
|
85 |
+
minimum=0.5,
|
86 |
+
maximum=2.0,
|
87 |
+
step=0.25,
|
88 |
+
value=1.0,
|
89 |
+
),
|
90 |
+
],
|
91 |
+
outputs=[
|
92 |
+
gr.Textbox(label="文件名 Filename"),
|
93 |
+
gr.Image(label="下载动图 Download GIF", type="filepath"),
|
94 |
+
],
|
95 |
+
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",
|
96 |
+
allow_flagging="never",
|
97 |
+
)
|
98 |
+
|
99 |
+
iface.launch()
|
requirements.txt
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
moviepy==1.0.3
|
2 |
+
gradio
|