File size: 5,039 Bytes
db3a622
 
34524fb
db3a622
34524fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a163be5
34524fb
 
 
 
db3a622
85e550a
 
 
 
db3a622
34524fb
db3a622
85e550a
 
 
 
34524fb
 
db3a622
34524fb
85e550a
34524fb
 
85e550a
34524fb
db3a622
34524fb
 
db3a622
34524fb
 
db3a622
34524fb
 
db3a622
34524fb
 
 
db3a622
34524fb
 
 
db3a622
34524fb
 
 
db3a622
34524fb
 
85e550a
db3a622
 
34524fb
 
 
 
db3a622
34524fb
 
 
a163be5
34524fb
db3a622
34524fb
db3a622
 
34524fb
 
 
db3a622
 
34524fb
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import gradio as gr
import moviepy.editor as mp
import imageio
import os
import logging

# 로그 설정
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

def get_video_info(video_path):
    try:
        clip = mp.VideoFileClip(video_path)
        duration = clip.duration
        logging.info(f"동영상 재생 시간: {duration}초")
        return duration
    except Exception as e:
        logging.error(f"동영상 정보 추출 실패: {e}")
        return None

def generate_thumbnails(video_path, start_time, end_time):
    try:
        clip = mp.VideoFileClip(video_path)
        start_frame = clip.get_frame(start_time)
        end_frame = clip.get_frame(end_time)
        start_thumb_path = "start_thumbnail.png"
        end_thumb_path = "end_thumbnail.png"
        imageio.imwrite(start_thumb_path, start_frame)
        imageio.imwrite(end_thumb_path, end_frame)
        logging.info("썸네일 생성 성공")
        return start_thumb_path, end_thumb_path
    except Exception as e:
        logging.error(f"썸네일 생성 실패: {e}")
        return None, None

def create_gif(video_path, start_time, end_time, resolution, fps, speed, repeat):
    try:
        clip = mp.VideoFileClip(video_path).subclip(start_time, end_time)
        # 해상도 조절
        if resolution != 100:
            new_width = int(clip.w * resolution / 100)
            new_height = int(clip.h * resolution / 100)
            clip = clip.resize(newsize=(new_width, new_height))
            logging.info(f"해상도 조절: {new_width}x{new_height}")
        # 프레임 속도 조절
        clip = clip.set_fps(fps)
        logging.info(f"프레임 속도 조절: {fps}fps")
        # 재생 속도 조절
        clip = clip.fx(mp.vfx.speedx, speed)
        logging.info(f"재생 속도 조절: {speed}배속")
        # GIF 반복 설정
        if repeat == -1:
            loop = 0  # 무한 반복
        else:
            loop = repeat
        gif_path = "output.gif"
        clip.write_gif(gif_path, loop=loop)
        logging.info("GIF 생성 성공")
        return gif_path
    except Exception as e:
        logging.error(f"GIF 생성 실패: {e}")
        return None

def process_video(video, start_time, end_time, resolution, fps, speed, repeat):
    if video is None:
        logging.warning("업로드된 동영상이 없습니다.")
        return None, None

    video_path = video  # 수정: video.name → video
    logging.info(f"동영상 업로드: {video_path}")

    # 동영상 정보 추출
    duration = get_video_info(video_path)

    if duration is None:
        logging.error("동영상 정보를 가져올 수 없습니다.")
        return None, None

    # 썸네일 생성
    start_thumb, end_thumb = generate_thumbnails(video_path, start_time, end_time)

    if not start_thumb or not end_thumb:
        logging.error("썸네일 생성에 실패했습니다.")
        return None, None

    # GIF 생성
    gif_path = create_gif(video_path, start_time, end_time, resolution, fps, speed, repeat)

    if gif_path:
        logging.info(f"생성된 GIF 경로: {gif_path}")
        return gif_path, gif_path
    else:
        logging.error("GIF 생성에 실패했습니다.")
        return None, None

with gr.Blocks() as demo:
    gr.Markdown("# 동영상을 GIF로 변환하기")

    with gr.Row():
        video_input = gr.Video(label="동영상 업로드")

    with gr.Row():
        video_info = gr.Textbox(label="동영상 재생 시간 (초)", interactive=False)

    with gr.Row():
        start_time = gr.Number(label="시작 시간 (초)", value=0)
        end_time = gr.Number(label="끝 시간 (초)", value=5)

    with gr.Row():
        start_thumbnail = gr.Image(label="시작 부분 썸네일")
        end_thumbnail = gr.Image(label="끝 부분 썸네일")

    with gr.Row():
        resolution = gr.Slider(label="해상도 조절 (%)", minimum=10, maximum=200, step=10, value=100)
        fps = gr.Slider(label="프레임 속도 조절", minimum=1, maximum=60, step=1, value=24)

    with gr.Row():
        speed = gr.Slider(label="재생 속도 조절", minimum=0.5, maximum=3.0, step=0.1, value=1.0)
        repeat = gr.Slider(label="GIF 반복 횟수 (-1은 무한 반복)", minimum=-1, maximum=10, step=1, value=-1)

    generate_button = gr.Button("GIF 생성")
    
    with gr.Row():
        gif_preview = gr.Image(label="GIF 미리보기")
        gif_download = gr.File(label="GIF 다운로드")

    def update_video_info(video):
        if video is None:
            return ""
        duration = get_video_info(video)  # 수정: video.name → video
        return f"{duration:.2f} 초" if duration else "정보 불러오기 실패"

    video_input.change(fn=update_video_info, inputs=video_input, outputs=video_info)

    generate_button.click(
        fn=process_video,
        inputs=[video_input, start_time, end_time, resolution, fps, speed, repeat],
        outputs=[gif_preview, gif_download]
    )

demo.launch()