Update app.py
Browse files
app.py
CHANGED
@@ -35,8 +35,9 @@ def generate_thumbnail(video_clip, time_point):
|
|
35 |
frame = video_clip.get_frame(time_point)
|
36 |
thumbnail_img = Image.fromarray(frame)
|
37 |
return thumbnail_img
|
38 |
-
except:
|
39 |
-
|
|
|
40 |
frame = video_clip.get_frame(0)
|
41 |
thumbnail_img = Image.fromarray(frame)
|
42 |
return thumbnail_img
|
@@ -52,25 +53,28 @@ def process_video(video,
|
|
52 |
μ 체 GIF λ³ν κ³Όμ μ μννλ ν¨μ
|
53 |
"""
|
54 |
global global_logs
|
55 |
-
global_logs = [] # νΈμΆ μλ§λ€
|
56 |
|
57 |
-
# λ‘κ·Έ 1: μ
λ‘λλ νμΌ νμΈ
|
58 |
add_log("[LOG 1] λΉλμ€ μ
λ‘λ λ° μ²λ¦¬ μμ")
|
59 |
|
60 |
-
#
|
|
|
|
|
61 |
add_log("[LOG 2] λΉλμ€ λ‘λ μ€...")
|
62 |
-
|
|
|
|
|
|
|
|
|
63 |
|
64 |
-
# μ¬μμκ° μΆλ ₯
|
65 |
duration = input_video.duration
|
66 |
add_log(f"[LOG 3] μ
λ‘λλ μμμ μ¬μμκ°: {duration:.2f}μ΄")
|
67 |
|
68 |
-
# μμ/λ μκ° parse
|
69 |
add_log("[LOG 4] μμ/λ μκ° νμ± μ€...")
|
70 |
start_sec = parse_time_to_seconds(start_time_str)
|
71 |
end_sec = parse_time_to_seconds(end_time_str)
|
72 |
|
73 |
-
#
|
74 |
if start_sec < 0:
|
75 |
start_sec = 0
|
76 |
if end_sec <= 0 or end_sec > duration:
|
@@ -81,44 +85,43 @@ def process_video(video,
|
|
81 |
|
82 |
add_log(f"[LOG 5] μ μ©λ μμ μκ°: {start_sec}μ΄, μ’
λ£ μκ°: {end_sec}μ΄")
|
83 |
|
84 |
-
# ν΄λΉ κ΅¬κ° μλ₯΄κΈ°(subclip)
|
85 |
add_log("[LOG 6] μμ μλ₯΄κΈ° μμ
μ§ν...")
|
86 |
clip = input_video.subclip(start_sec, end_sec)
|
87 |
|
88 |
-
# μλ μ‘°μ
|
89 |
if abs(speed_factor - 1.0) > 1e-3:
|
90 |
add_log(f"[LOG 7] μλ {speed_factor}λ°°λ‘ μ‘°μ μ€...")
|
91 |
clip = clip.fx(mp.vfx.speedx, speed_factor)
|
92 |
|
93 |
-
# ν΄μλ μ‘°μ (κΈ°λ³Έ 1.0 = μλ³Έ)
|
94 |
if abs(resolution_factor - 1.0) > 1e-3:
|
95 |
add_log(f"[LOG 8] ν΄μλ {resolution_factor*100:.1f}%λ‘ μ‘°μ μ€...")
|
96 |
clip = clip.resize(resolution_factor)
|
97 |
|
98 |
-
# νλ μ λ μ΄νΈ μ‘°μ (κΈ°λ³Έ μλ³Έ fps)
|
99 |
original_fps = clip.fps
|
100 |
target_fps = original_fps * frame_rate_factor
|
101 |
add_log(f"[LOG 9] νλ μ λ μ΄νΈλ₯Ό {target_fps:.2f}λ‘ μ‘°μ μ€... (μλ³Έ {original_fps} FPS)")
|
102 |
clip = clip.set_fps(target_fps)
|
103 |
|
104 |
-
# λ°λ³΅ νμ (μ΅λ 10ν)
|
105 |
repeat_count = min(max(int(repeat_count), 1), 10)
|
106 |
add_log(f"[LOG 10] λ°λ³΅ νμ: {repeat_count}ν")
|
107 |
|
108 |
repeated_clips = [clip] * repeat_count
|
109 |
final_clip = mp.concatenate_videoclips(repeated_clips)
|
110 |
|
111 |
-
# GIF μμ±
|
112 |
add_log("[LOG 11] GIF μμ± μ€...")
|
113 |
-
# μμ νμΌ μ΄λ¦ μμ±
|
114 |
output_filename = f"temp_{uuid.uuid4().hex}.gif"
|
115 |
|
116 |
-
|
117 |
-
|
118 |
-
|
|
|
|
|
|
|
119 |
|
120 |
-
|
121 |
-
|
|
|
|
|
|
|
122 |
|
123 |
return gif_preview, output_filename, "\n".join(global_logs)
|
124 |
|
@@ -126,12 +129,18 @@ def update_thumbnails(video, start_time_str, end_time_str):
|
|
126 |
"""
|
127 |
μμ/λ μΈλ€μΌμ μ
λ°μ΄νΈνκΈ° μν ν¨μ
|
128 |
"""
|
129 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
duration = input_video.duration
|
131 |
|
132 |
start_sec = parse_time_to_seconds(start_time_str)
|
133 |
end_sec = parse_time_to_seconds(end_time_str)
|
134 |
-
# λ²μ 보μ
|
135 |
if start_sec < 0:
|
136 |
start_sec = 0
|
137 |
if end_sec <= 0 or end_sec > duration:
|
@@ -152,76 +161,46 @@ with gr.Blocks() as demo:
|
|
152 |
gr.Markdown("## λμμμ GIFλ‘ λ³ννκΈ° λ°λͺ¨")
|
153 |
|
154 |
with gr.Tab("GIF λ³ν"):
|
155 |
-
#
|
156 |
video_input = gr.Video(label="λμμ μ
λ‘λ")
|
157 |
-
|
158 |
-
# 4. μμ/λ λΆλΆ μκ° μ
λ ₯
|
159 |
start_time = gr.Textbox(label="μμ μκ° (μ: 00:00:05)", value="00:00:00")
|
160 |
end_time = gr.Textbox(label="μ’
λ£ μκ° (μ: 00:00:10)", value="00:00:05")
|
161 |
-
|
162 |
-
# 미리보기 μΈλ€μΌ (μμ, μ’
λ£)
|
163 |
start_thumb_output = gr.Image(label="μμ μΈλ€μΌ 미리보기")
|
164 |
end_thumb_output = gr.Image(label="μ’
λ£ μΈλ€μΌ 미리보기")
|
165 |
-
|
166 |
-
# 6. ν΄μλ μ‘°μ μ¬λΌμ΄λ(κΈ°λ³Έ 1.0)
|
167 |
resolution_slider = gr.Slider(label="ν΄μλ λΉμ¨ μ‘°μ (0.1 ~ 1.0)", minimum=0.1, maximum=1.0, step=0.1, value=1.0)
|
168 |
-
|
169 |
-
# 7. νλ μ μλ μ‘°μ μ¬λΌμ΄λ(κΈ°λ³Έ 1.0)
|
170 |
fps_slider = gr.Slider(label="νλ μ λ μ΄νΈ λ°°μ¨ μ‘°μ (0.1 ~ 2.0)", minimum=0.1, maximum=2.0, step=0.1, value=1.0)
|
171 |
-
|
172 |
-
# 8. μλ μ‘°μ μ¬λΌμ΄λ(κΈ°λ³Έ 1λ°°)
|
173 |
speed_slider = gr.Slider(label="μ¬μ μλ μ‘°μ (0.5 ~ 2.0)", minimum=0.5, maximum=2.0, step=0.1, value=1.0)
|
174 |
-
|
175 |
-
# 9. λ°λ³΅ νμ
|
176 |
repeat_slider = gr.Slider(label="GIF λ°λ³΅ νμ(1 ~ 10)", minimum=1, maximum=10, step=1, value=1)
|
177 |
-
|
178 |
-
# 10. GIF μμ± λ²νΌ
|
179 |
generate_button = gr.Button("GIF μμ±νκΈ°")
|
180 |
-
|
181 |
-
# 11, 12. κ²°κ³Ό 미리보기(μ΄λ―Έμ§), λ€μ΄λ‘λ(λ§ν¬)
|
182 |
gif_preview_output = gr.Image(label="μμ±λ GIF 미리보기")
|
183 |
download_output = gr.File(label="GIF λ€μ΄λ‘λ λ§ν¬")
|
184 |
-
|
185 |
-
# λ‘κ·Έ μΆλ ₯
|
186 |
logs_output = gr.Textbox(label="λ‘κ·Έ μΆλ ₯", lines=10)
|
187 |
|
188 |
-
# μΈλ€μΌ μ
λ°μ΄νΈ μ΄λ²€νΈ
|
189 |
-
start_time.change(
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
video_input,
|
210 |
-
start_time,
|
211 |
-
end_time,
|
212 |
-
resolution_slider,
|
213 |
-
fps_slider,
|
214 |
-
speed_slider,
|
215 |
-
repeat_slider
|
216 |
-
],
|
217 |
-
outputs=[
|
218 |
-
gif_preview_output,
|
219 |
-
download_output,
|
220 |
-
logs_output
|
221 |
-
]
|
222 |
-
)
|
223 |
-
|
224 |
-
gr.Markdown("### [μ¬μ© κ°μ΄λ]\n1. λμμμ μ
λ‘λνμΈμ.\n2. μμ/λ μκ°μ μ μ ν μ
λ ₯νμΈμ.\n3. ν΄μλ, νλ μ μλ, μ¬μ μλ, λ°λ³΅ νμλ₯Ό μ‘°μ ν λ€ `GIF μμ±νκΈ°` λ²νΌμ λλ₯΄λ©΄ GIFκ° μμ±λ©λλ€.\n4. κ²°κ³Ό 미리보기μ λ€μ΄λ‘λ λ§ν¬λ₯Ό ν΅ν΄ GIFλ₯Ό νμΈν μ μμ΅λλ€.")
|
225 |
|
226 |
if __name__ == "__main__":
|
227 |
demo.launch()
|
|
|
35 |
frame = video_clip.get_frame(time_point)
|
36 |
thumbnail_img = Image.fromarray(frame)
|
37 |
return thumbnail_img
|
38 |
+
except Exception as e:
|
39 |
+
add_log(f"[ERROR] μΈλ€μΌ μμ± μ€ν¨: {e}")
|
40 |
+
# time_pointκ° λ²μλ₯Ό λ²μ΄λλ©΄ 첫 νλ μμ λ°ν
|
41 |
frame = video_clip.get_frame(0)
|
42 |
thumbnail_img = Image.fromarray(frame)
|
43 |
return thumbnail_img
|
|
|
53 |
μ 체 GIF λ³ν κ³Όμ μ μννλ ν¨μ
|
54 |
"""
|
55 |
global global_logs
|
56 |
+
global_logs = [] # νΈμΆ μλ§λ€ λ‘κ·Έ μ΄κΈ°ν
|
57 |
|
|
|
58 |
add_log("[LOG 1] λΉλμ€ μ
λ‘λ λ° μ²λ¦¬ μμ")
|
59 |
|
60 |
+
# video νλΌλ―Έν°μμ νμΌ κ²½λ‘ μΆμΆ
|
61 |
+
video_path = video if isinstance(video, str) else video.name
|
62 |
+
|
63 |
add_log("[LOG 2] λΉλμ€ λ‘λ μ€...")
|
64 |
+
try:
|
65 |
+
input_video = mp.VideoFileClip(video_path)
|
66 |
+
except Exception as e:
|
67 |
+
add_log(f"[ERROR] λΉλμ€ λ‘λ μ€ν¨: {e}")
|
68 |
+
return None, None, "\n".join(global_logs)
|
69 |
|
|
|
70 |
duration = input_video.duration
|
71 |
add_log(f"[LOG 3] μ
λ‘λλ μμμ μ¬μμκ°: {duration:.2f}μ΄")
|
72 |
|
|
|
73 |
add_log("[LOG 4] μμ/λ μκ° νμ± μ€...")
|
74 |
start_sec = parse_time_to_seconds(start_time_str)
|
75 |
end_sec = parse_time_to_seconds(end_time_str)
|
76 |
|
77 |
+
# λ²μ 보μ
|
78 |
if start_sec < 0:
|
79 |
start_sec = 0
|
80 |
if end_sec <= 0 or end_sec > duration:
|
|
|
85 |
|
86 |
add_log(f"[LOG 5] μ μ©λ μμ μκ°: {start_sec}μ΄, μ’
λ£ μκ°: {end_sec}μ΄")
|
87 |
|
|
|
88 |
add_log("[LOG 6] μμ μλ₯΄κΈ° μμ
μ§ν...")
|
89 |
clip = input_video.subclip(start_sec, end_sec)
|
90 |
|
|
|
91 |
if abs(speed_factor - 1.0) > 1e-3:
|
92 |
add_log(f"[LOG 7] μλ {speed_factor}λ°°λ‘ μ‘°μ μ€...")
|
93 |
clip = clip.fx(mp.vfx.speedx, speed_factor)
|
94 |
|
|
|
95 |
if abs(resolution_factor - 1.0) > 1e-3:
|
96 |
add_log(f"[LOG 8] ν΄μλ {resolution_factor*100:.1f}%λ‘ μ‘°μ μ€...")
|
97 |
clip = clip.resize(resolution_factor)
|
98 |
|
|
|
99 |
original_fps = clip.fps
|
100 |
target_fps = original_fps * frame_rate_factor
|
101 |
add_log(f"[LOG 9] νλ μ λ μ΄νΈλ₯Ό {target_fps:.2f}λ‘ μ‘°μ μ€... (μλ³Έ {original_fps} FPS)")
|
102 |
clip = clip.set_fps(target_fps)
|
103 |
|
|
|
104 |
repeat_count = min(max(int(repeat_count), 1), 10)
|
105 |
add_log(f"[LOG 10] λ°λ³΅ νμ: {repeat_count}ν")
|
106 |
|
107 |
repeated_clips = [clip] * repeat_count
|
108 |
final_clip = mp.concatenate_videoclips(repeated_clips)
|
109 |
|
|
|
110 |
add_log("[LOG 11] GIF μμ± μ€...")
|
|
|
111 |
output_filename = f"temp_{uuid.uuid4().hex}.gif"
|
112 |
|
113 |
+
try:
|
114 |
+
final_clip.write_gif(output_filename, fps=target_fps)
|
115 |
+
add_log("[LOG 12] GIF μμ± μλ£! νμΌλͺ
: " + output_filename)
|
116 |
+
except Exception as e:
|
117 |
+
add_log(f"[ERROR] GIF μμ± μ€ν¨: {e}")
|
118 |
+
return None, None, "\n".join(global_logs)
|
119 |
|
120 |
+
try:
|
121 |
+
gif_preview = Image.open(output_filename)
|
122 |
+
except Exception as e:
|
123 |
+
add_log(f"[ERROR] GIF 미리보기 μ΄λ―Έμ§ μμ± μ€ν¨: {e}")
|
124 |
+
gif_preview = None
|
125 |
|
126 |
return gif_preview, output_filename, "\n".join(global_logs)
|
127 |
|
|
|
129 |
"""
|
130 |
μμ/λ μΈλ€μΌμ μ
λ°μ΄νΈνκΈ° μν ν¨μ
|
131 |
"""
|
132 |
+
video_path = video if isinstance(video, str) else video.name
|
133 |
+
|
134 |
+
try:
|
135 |
+
input_video = mp.VideoFileClip(video_path)
|
136 |
+
except Exception as e:
|
137 |
+
add_log(f"[ERROR] λΉλμ€ λ‘λ μ€ν¨: {e}")
|
138 |
+
return None, None
|
139 |
+
|
140 |
duration = input_video.duration
|
141 |
|
142 |
start_sec = parse_time_to_seconds(start_time_str)
|
143 |
end_sec = parse_time_to_seconds(end_time_str)
|
|
|
144 |
if start_sec < 0:
|
145 |
start_sec = 0
|
146 |
if end_sec <= 0 or end_sec > duration:
|
|
|
161 |
gr.Markdown("## λμμμ GIFλ‘ λ³ννκΈ° λ°λͺ¨")
|
162 |
|
163 |
with gr.Tab("GIF λ³ν"):
|
164 |
+
# λμμ μ
λ‘λ
|
165 |
video_input = gr.Video(label="λμμ μ
λ‘λ")
|
166 |
+
# μμ/λ μκ° μ
λ ₯
|
|
|
167 |
start_time = gr.Textbox(label="μμ μκ° (μ: 00:00:05)", value="00:00:00")
|
168 |
end_time = gr.Textbox(label="μ’
λ£ μκ° (μ: 00:00:10)", value="00:00:05")
|
169 |
+
# μΈλ€μΌ 미리보기
|
|
|
170 |
start_thumb_output = gr.Image(label="μμ μΈλ€μΌ 미리보기")
|
171 |
end_thumb_output = gr.Image(label="μ’
λ£ μΈλ€μΌ 미리보기")
|
172 |
+
# ν΄μλ, νλ μ λ μ΄νΈ, μ¬μ μλ, λ°λ³΅ νμ μ‘°μ
|
|
|
173 |
resolution_slider = gr.Slider(label="ν΄μλ λΉμ¨ μ‘°μ (0.1 ~ 1.0)", minimum=0.1, maximum=1.0, step=0.1, value=1.0)
|
|
|
|
|
174 |
fps_slider = gr.Slider(label="νλ μ λ μ΄νΈ λ°°μ¨ μ‘°μ (0.1 ~ 2.0)", minimum=0.1, maximum=2.0, step=0.1, value=1.0)
|
|
|
|
|
175 |
speed_slider = gr.Slider(label="μ¬μ μλ μ‘°μ (0.5 ~ 2.0)", minimum=0.5, maximum=2.0, step=0.1, value=1.0)
|
|
|
|
|
176 |
repeat_slider = gr.Slider(label="GIF λ°λ³΅ νμ(1 ~ 10)", minimum=1, maximum=10, step=1, value=1)
|
177 |
+
# GIF μμ± λ²νΌ λ° κ²°κ³Ό μΆλ ₯
|
|
|
178 |
generate_button = gr.Button("GIF μμ±νκΈ°")
|
|
|
|
|
179 |
gif_preview_output = gr.Image(label="μμ±λ GIF 미리보기")
|
180 |
download_output = gr.File(label="GIF λ€μ΄λ‘λ λ§ν¬")
|
|
|
|
|
181 |
logs_output = gr.Textbox(label="λ‘κ·Έ μΆλ ₯", lines=10)
|
182 |
|
183 |
+
# μΈλ€μΌ μ
λ°μ΄νΈ μ΄λ²€νΈ (μ
λ ₯ μκ°μ΄λ λμμμ΄ λ³κ²½λ λ)
|
184 |
+
start_time.change(fn=update_thumbnails,
|
185 |
+
inputs=[video_input, start_time, end_time],
|
186 |
+
outputs=[start_thumb_output, end_thumb_output])
|
187 |
+
end_time.change(fn=update_thumbnails,
|
188 |
+
inputs=[video_input, start_time, end_time],
|
189 |
+
outputs=[start_thumb_output, end_thumb_output])
|
190 |
+
video_input.change(fn=update_thumbnails,
|
191 |
+
inputs=[video_input, start_time, end_time],
|
192 |
+
outputs=[start_thumb_output, end_thumb_output])
|
193 |
+
# GIF μμ± λ²νΌ μ΄λ²€νΈ
|
194 |
+
generate_button.click(fn=process_video,
|
195 |
+
inputs=[video_input, start_time, end_time,
|
196 |
+
resolution_slider, fps_slider, speed_slider, repeat_slider],
|
197 |
+
outputs=[gif_preview_output, download_output, logs_output])
|
198 |
+
|
199 |
+
gr.Markdown("### [μ¬μ© κ°μ΄λ]\n"
|
200 |
+
"1. λμμμ μ
λ‘λνμΈμ.\n"
|
201 |
+
"2. μμ/λ μκ°μ μ μ ν μ
λ ₯νμΈμ.\n"
|
202 |
+
"3. ν΄μλ, νλ μ μλ, μ¬μ μλ, λ°λ³΅ νμλ₯Ό μ‘°μ ν λ€ `GIF μμ±νκΈ°` λ²νΌμ λλ₯΄λ©΄ GIFκ° μμ±λ©λλ€.\n"
|
203 |
+
"4. κ²°κ³Ό 미리보기μ λ€μ΄λ‘λ λ§ν¬λ₯Ό ν΅ν΄ GIFλ₯Ό νμΈν μ μμ΅λλ€.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
|
205 |
if __name__ == "__main__":
|
206 |
demo.launch()
|