|
import os |
|
import uuid |
|
import moviepy.editor as mp |
|
from PIL import Image |
|
import gradio as gr |
|
|
|
|
|
|
|
|
|
global_logs = [] |
|
|
|
def add_log(message: str): |
|
""" |
|
๋ก๊ทธ ๋ฉ์์ง๋ฅผ ์ ์ฅํ๋ ํจ์ |
|
""" |
|
global_logs.append(message) |
|
print(message) |
|
|
|
def parse_time_to_seconds(time_str: str): |
|
""" |
|
์:๋ถ:์ด ํํ์ ๋ฌธ์์ด(์: '00:00:10' ๋๋ '00:01:02')์ ์ด ๋จ์(float)๋ก ๋ณํ |
|
""" |
|
try: |
|
h, m, s = time_str.split(":") |
|
total_seconds = int(h) * 3600 + int(m) * 60 + float(s) |
|
return total_seconds |
|
except Exception: |
|
return 0.0 |
|
|
|
def generate_thumbnail(video_clip, time_point): |
|
""" |
|
ํน์ ์์ ์ ํ๋ ์์ ์ธ๋ค์ผ๋ก ์์ฑํ์ฌ PIL.Image๋ก ๋ฐํ |
|
""" |
|
try: |
|
frame = video_clip.get_frame(time_point) |
|
thumbnail_img = Image.fromarray(frame) |
|
return thumbnail_img |
|
except: |
|
|
|
frame = video_clip.get_frame(0) |
|
thumbnail_img = Image.fromarray(frame) |
|
return thumbnail_img |
|
|
|
def process_video(video, |
|
start_time_str, |
|
end_time_str, |
|
resolution_factor, |
|
frame_rate_factor, |
|
speed_factor, |
|
repeat_count): |
|
""" |
|
์ ์ฒด GIF ๋ณํ ๊ณผ์ ์ ์ํํ๋ ํจ์ |
|
""" |
|
global global_logs |
|
global_logs = [] |
|
|
|
|
|
add_log("[LOG 1] ๋น๋์ค ์
๋ก๋ ๋ฐ ์ฒ๋ฆฌ ์์") |
|
|
|
|
|
add_log("[LOG 2] ๋น๋์ค ๋ก๋ ์ค...") |
|
input_video = mp.VideoFileClip(video.name) |
|
|
|
|
|
duration = input_video.duration |
|
add_log(f"[LOG 3] ์
๋ก๋๋ ์์์ ์ฌ์์๊ฐ: {duration:.2f}์ด") |
|
|
|
|
|
add_log("[LOG 4] ์์/๋ ์๊ฐ ํ์ฑ ์ค...") |
|
start_sec = parse_time_to_seconds(start_time_str) |
|
end_sec = parse_time_to_seconds(end_time_str) |
|
|
|
|
|
if start_sec < 0: |
|
start_sec = 0 |
|
if end_sec <= 0 or end_sec > duration: |
|
end_sec = duration |
|
if start_sec >= end_sec: |
|
start_sec = 0 |
|
end_sec = duration |
|
|
|
add_log(f"[LOG 5] ์ ์ฉ๋ ์์ ์๊ฐ: {start_sec}์ด, ์ข
๋ฃ ์๊ฐ: {end_sec}์ด") |
|
|
|
|
|
add_log("[LOG 6] ์์ ์๋ฅด๊ธฐ ์์
์งํ...") |
|
clip = input_video.subclip(start_sec, end_sec) |
|
|
|
|
|
if abs(speed_factor - 1.0) > 1e-3: |
|
add_log(f"[LOG 7] ์๋ {speed_factor}๋ฐฐ๋ก ์กฐ์ ์ค...") |
|
clip = clip.fx(mp.vfx.speedx, speed_factor) |
|
|
|
|
|
if abs(resolution_factor - 1.0) > 1e-3: |
|
add_log(f"[LOG 8] ํด์๋ {resolution_factor*100:.1f}%๋ก ์กฐ์ ์ค...") |
|
clip = clip.resize(resolution_factor) |
|
|
|
|
|
original_fps = clip.fps |
|
target_fps = original_fps * frame_rate_factor |
|
add_log(f"[LOG 9] ํ๋ ์ ๋ ์ดํธ๋ฅผ {target_fps:.2f}๋ก ์กฐ์ ์ค... (์๋ณธ {original_fps} FPS)") |
|
clip = clip.set_fps(target_fps) |
|
|
|
|
|
repeat_count = min(max(int(repeat_count), 1), 10) |
|
add_log(f"[LOG 10] ๋ฐ๋ณต ํ์: {repeat_count}ํ") |
|
|
|
repeated_clips = [clip] * repeat_count |
|
final_clip = mp.concatenate_videoclips(repeated_clips) |
|
|
|
|
|
add_log("[LOG 11] GIF ์์ฑ ์ค...") |
|
|
|
output_filename = f"temp_{uuid.uuid4().hex}.gif" |
|
|
|
final_clip.write_gif(output_filename, fps=target_fps) |
|
|
|
add_log("[LOG 12] GIF ์์ฑ ์๋ฃ! ํ์ผ๋ช
: " + output_filename) |
|
|
|
|
|
gif_preview = Image.open(output_filename) |
|
|
|
return gif_preview, output_filename, "\n".join(global_logs) |
|
|
|
def update_thumbnails(video, start_time_str, end_time_str): |
|
""" |
|
์์/๋ ์ธ๋ค์ผ์ ์
๋ฐ์ดํธํ๊ธฐ ์ํ ํจ์ |
|
""" |
|
input_video = mp.VideoFileClip(video.name) |
|
duration = input_video.duration |
|
|
|
start_sec = parse_time_to_seconds(start_time_str) |
|
end_sec = parse_time_to_seconds(end_time_str) |
|
|
|
if start_sec < 0: |
|
start_sec = 0 |
|
if end_sec <= 0 or end_sec > duration: |
|
end_sec = duration |
|
if start_sec >= end_sec: |
|
start_sec = 0 |
|
end_sec = duration |
|
|
|
start_thumb = generate_thumbnail(input_video, start_sec) |
|
end_thumb = generate_thumbnail(input_video, end_sec) |
|
|
|
return start_thumb, end_thumb |
|
|
|
|
|
|
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("## ๋์์์ GIF๋ก ๋ณํํ๊ธฐ ๋ฐ๋ชจ") |
|
|
|
with gr.Tab("GIF ๋ณํ"): |
|
|
|
video_input = gr.Video(label="๋์์ ์
๋ก๋", type="file") |
|
|
|
|
|
start_time = gr.Textbox(label="์์ ์๊ฐ (์: 00:00:05)", value="00:00:00") |
|
end_time = gr.Textbox(label="์ข
๋ฃ ์๊ฐ (์: 00:00:10)", value="00:00:05") |
|
|
|
|
|
start_thumb_output = gr.Image(label="์์ ์ธ๋ค์ผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ") |
|
end_thumb_output = gr.Image(label="์ข
๋ฃ ์ธ๋ค์ผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ") |
|
|
|
|
|
resolution_slider = gr.Slider(label="ํด์๋ ๋น์จ ์กฐ์ (0.1 ~ 1.0)", minimum=0.1, maximum=1.0, step=0.1, value=1.0) |
|
|
|
|
|
fps_slider = gr.Slider(label="ํ๋ ์ ๋ ์ดํธ ๋ฐฐ์จ ์กฐ์ (0.1 ~ 2.0)", minimum=0.1, maximum=2.0, step=0.1, value=1.0) |
|
|
|
|
|
speed_slider = gr.Slider(label="์ฌ์ ์๋ ์กฐ์ (0.5 ~ 2.0)", minimum=0.5, maximum=2.0, step=0.1, value=1.0) |
|
|
|
|
|
repeat_slider = gr.Slider(label="GIF ๋ฐ๋ณต ํ์(1 ~ 10)", minimum=1, maximum=10, step=1, value=1) |
|
|
|
|
|
generate_button = gr.Button("GIF ์์ฑํ๊ธฐ") |
|
|
|
|
|
gif_preview_output = gr.Image(label="์์ฑ๋ GIF ๋ฏธ๋ฆฌ๋ณด๊ธฐ") |
|
download_output = gr.File(label="GIF ๋ค์ด๋ก๋ ๋งํฌ") |
|
|
|
|
|
logs_output = gr.Textbox(label="๋ก๊ทธ ์ถ๋ ฅ", lines=10) |
|
|
|
|
|
|
|
start_time.change( |
|
fn=update_thumbnails, |
|
inputs=[video_input, start_time, end_time], |
|
outputs=[start_thumb_output, end_thumb_output] |
|
) |
|
end_time.change( |
|
fn=update_thumbnails, |
|
inputs=[video_input, start_time, end_time], |
|
outputs=[start_thumb_output, end_thumb_output] |
|
) |
|
|
|
|
|
video_input.change( |
|
fn=update_thumbnails, |
|
inputs=[video_input, start_time, end_time], |
|
outputs=[start_thumb_output, end_thumb_output] |
|
) |
|
|
|
|
|
generate_button.click( |
|
fn=process_video, |
|
inputs=[ |
|
video_input, |
|
start_time, |
|
end_time, |
|
resolution_slider, |
|
fps_slider, |
|
speed_slider, |
|
repeat_slider |
|
], |
|
outputs=[ |
|
gif_preview_output, |
|
download_output, |
|
logs_output |
|
] |
|
) |
|
|
|
gr.Markdown("### [์ฌ์ฉ ๊ฐ์ด๋]\n1. ๋์์์ ์
๋ก๋ํ์ธ์.\n2. ์์/๋ ์๊ฐ์ ์ ์ ํ ์
๋ ฅํ์ธ์.\n3. ํด์๋, ํ๋ ์ ์๋, ์ฌ์ ์๋, ๋ฐ๋ณต ํ์๋ฅผ ์กฐ์ ํ ๋ค `GIF ์์ฑํ๊ธฐ` ๋ฒํผ์ ๋๋ฅด๋ฉด GIF๊ฐ ์์ฑ๋ฉ๋๋ค.\n4. ๊ฒฐ๊ณผ ๋ฏธ๋ฆฌ๋ณด๊ธฐ์ ๋ค์ด๋ก๋ ๋งํฌ๋ฅผ ํตํด GIF๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.") |
|
|
|
|
|
if __name__ == "__main__": |
|
demo.launch() |
|
|
|
|