admin commited on
Commit
065cfa4
·
0 Parent(s):

Initial commit

Browse files
Files changed (6) hide show
  1. .gitattributes +35 -0
  2. .gitignore +3 -0
  3. README.md +12 -0
  4. app.py +100 -0
  5. requirements.txt +1 -0
  6. utils.py +12 -0
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ *.gif
2
+ test.*
3
+ *__pycache__*
README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Video to Gif
3
+ emoji: 🎥
4
+ colorFrom: yellow
5
+ colorTo: gray
6
+ sdk: gradio
7
+ sdk_version: 5.22.0
8
+ app_file: app.py
9
+ pinned: false
10
+ short_description: Convert videos to GIFs
11
+ license: apache-2.0
12
+ ---
app.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import math
3
+ import gradio as gr
4
+ from PIL import Image, ImageSequence
5
+ from moviepy.editor import VideoFileClip
6
+ from utils import clean_dir, TMP_DIR, EN_US
7
+
8
+ ZH2EN = {
9
+ "倍速": "Speed",
10
+ "状态栏": "Status",
11
+ "文件名": "Filename",
12
+ "下载动图": "Download GIF",
13
+ "视频过长": "Video too long",
14
+ "视频转 GIF 动图": "Video to GIF",
15
+ "上传视频 (请确保完整上传再点击提交,若时长超过五秒可先在线裁剪)": "Upload video (please ensure the video is completely uploaded before clicking submit, you can crop it online to < 5s)",
16
+ }
17
+
18
+
19
+ def _L(zh_txt: str):
20
+ return ZH2EN[zh_txt] if EN_US else zh_txt
21
+
22
+
23
+ def get_frame_dur(gif: Image):
24
+ # 获取 GIF 图像中第一帧的 duration
25
+ dur = gif.info.get("duration", 100)
26
+ # 返回每一帧的 duration
27
+ return [frame.info.get("duration", dur) for frame in ImageSequence.Iterator(gif)]
28
+
29
+
30
+ def resize_gif(target_width: int, target_height: int, input_gif, output_gif):
31
+ gif = Image.open(input_gif)
32
+ modified_frames = []
33
+ for frame in ImageSequence.Iterator(gif):
34
+ resized_frame = frame.resize((target_width, target_height), Image.LANCZOS)
35
+ modified_frames.append(resized_frame)
36
+
37
+ frame_durations = get_frame_dur(gif)
38
+ # 将修改后的帧作为新的 GIF 保存
39
+ modified_frames[0].save(
40
+ output_gif,
41
+ format="GIF",
42
+ append_images=modified_frames[1:],
43
+ save_all=True,
44
+ duration=frame_durations,
45
+ loop=0,
46
+ )
47
+
48
+ return output_gif
49
+
50
+
51
+ # outer func
52
+ def infer(video_path: str, speed: float, target_w=640, cache=f"{TMP_DIR}/gif"):
53
+ status = "Success"
54
+ gif_name = gif_out = None
55
+ try:
56
+ clean_dir(cache)
57
+ with VideoFileClip(video_path, audio_fps=16000) as clip:
58
+ if clip.duration > 5:
59
+ raise ValueError(_L("视频过长"))
60
+
61
+ clip.speedx(speed).to_gif(f"{cache}/input.gif", fps=12)
62
+ w, h = clip.size
63
+
64
+ gif_in = f"{cache}/input.gif"
65
+ target_h = math.ceil(target_w * h / w)
66
+ gif_name = os.path.basename(video_path)
67
+ gif_out = resize_gif(target_w, target_h, gif_in, f"{cache}/output.gif")
68
+
69
+ except Exception as e:
70
+ status = f"{e}"
71
+
72
+ return status, gif_name, gif_out
73
+
74
+
75
+ if __name__ == "__main__":
76
+ example = (
77
+ "https://www.modelscope.cn/studio/Genius-Society/video2gif/resolve/master"
78
+ if EN_US
79
+ else "."
80
+ )
81
+ gr.Interface(
82
+ fn=infer,
83
+ inputs=[
84
+ gr.Video(
85
+ label=_L(
86
+ "上传视频 (请确保完整上传再点击提交,若时长超过五秒可先在线裁剪)"
87
+ )
88
+ ),
89
+ gr.Slider(label=_L("倍速"), minimum=0.5, maximum=2.0, step=0.25, value=1.0),
90
+ ],
91
+ outputs=[
92
+ gr.Textbox(label=_L("状态栏"), show_copy_button=True),
93
+ gr.Textbox(label=_L("文件名"), show_copy_button=True),
94
+ gr.Image(label=_L("下载动图"), type="filepath", show_share_button=False),
95
+ ],
96
+ flagging_mode="never",
97
+ examples=[[f"{example}/examples/herta.mp4", 2]],
98
+ cache_examples=False,
99
+ title=_L("视频转 GIF 动图"),
100
+ ).launch()
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ moviepy==1.0.3
utils.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+
4
+ EN_US = os.getenv("LANG") != "zh_CN.UTF-8"
5
+ TMP_DIR = "./__pycache__"
6
+
7
+
8
+ def clean_dir(dir_path: str):
9
+ if os.path.exists(dir_path):
10
+ shutil.rmtree(dir_path)
11
+
12
+ os.makedirs(dir_path)