File size: 3,099 Bytes
7cf86e5
 
 
 
 
35429ce
7cf86e5
 
9909b2f
7cf86e5
 
 
 
 
 
 
 
35429ce
7cf86e5
 
 
 
 
 
 
 
 
9909b2f
 
7cf86e5
 
 
 
 
 
 
 
9909b2f
7cf86e5
 
 
 
 
 
 
9909b2f
 
7cf86e5
 
 
 
9909b2f
7cf86e5
 
 
 
 
 
 
 
 
9909b2f
7cf86e5
 
9909b2f
7cf86e5
 
 
 
9909b2f
7cf86e5
 
 
b0b394a
 
35429ce
b0b394a
 
7cf86e5
 
 
b0b394a
 
9909b2f
b0b394a
 
7cf86e5
 
 
 
 
 
 
 
b0b394a
3359abb
7cf86e5
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
97
98
import os
import math
import gradio as gr
from PIL import Image, ImageSequence
from moviepy.editor import VideoFileClip
from utils import clean_dir, TMP_DIR, EN_US

ZH2EN = {
    "上传视频 (请确保上传完整后再点击提交,若时长大于五秒可先在线裁剪)": "Upload video (please ensure the video is completely uploaded before clicking submit, you can crop it online to less than 5s)",
    "倍速": "Speed",
    "状态栏": "Status",
    "文件名": "Filename",
    "下载动图": "Download GIF",
}


def _L(zh_txt: str):
    return ZH2EN[zh_txt] if EN_US else zh_txt


def get_frame_dur(gif: Image):
    # 获取 GIF 图像中第一帧的 duration
    dur = gif.info.get("duration", 100)
    # 返回每一帧的 duration
    return [frame.info.get("duration", dur) for frame in ImageSequence.Iterator(gif)]


def resize_gif(target_width: int, target_height: int, input_gif, output_gif):
    gif = Image.open(input_gif)
    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_dur(gif)
    # 将修改后的帧作为新的 GIF 保存
    modified_frames[0].save(
        output_gif,
        format="GIF",
        append_images=modified_frames[1:],
        save_all=True,
        duration=frame_durations,
        loop=0,
    )

    return output_gif


# outer func
def infer(video_path: str, speed: float, target_w=640, cache=f"{TMP_DIR}/gif"):
    status = "Success"
    gif_name = gif_out = None
    try:
        clean_dir(cache)
        with VideoFileClip(video_path, audio_fps=16000) as clip:
            if clip.duration > 5:
                raise ValueError("上传的视频过长")

            clip.speedx(speed).to_gif(f"{cache}/input.gif", fps=12)
            w, h = clip.size

        gif_in = f"{cache}/input.gif"
        target_h = math.ceil(target_w * h / w)
        gif_name = os.path.basename(video_path)
        gif_out = resize_gif(target_w, target_h, gif_in, f"{cache}/output.gif")

    except Exception as e:
        status = f"{e}"

    return status, gif_name, gif_out


def video2gif():
    example = (
        "https://www.modelscope.cn/studio/Genius-Society/online_tools/resolve/master"
        if EN_US
        else "."
    )
    return gr.Interface(
        fn=infer,
        inputs=[
            gr.Video(
                label=_L(
                    "上传视频 (请确保上传完整后再点击提交,若时长大于五秒可先在线裁剪)"
                )
            ),
            gr.Slider(label=_L("倍速"), minimum=0.5, maximum=2.0, step=0.25, value=1.0),
        ],
        outputs=[
            gr.Textbox(label=_L("状态栏"), show_copy_button=True),
            gr.Textbox(label=_L("文件名"), show_copy_button=True),
            gr.Image(label=_L("下载动图"), type="filepath", show_share_button=False),
        ],
        flagging_mode="never",
        examples=[[f"{example}/examples/herta.mp4", 2]],
        cache_examples=False,
    )