Spaces:
Sleeping
Sleeping
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() | |