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()