Spaces:
Runtime error
Runtime error
update video concatenation logic
Browse files
app.py
CHANGED
|
@@ -235,6 +235,10 @@ def process_final_combination(audio_in, chosen_translated, volume, cut_start, vi
|
|
| 235 |
else:
|
| 236 |
return gr.update(value=temp_output_path, visible=True), gr.update(visible=False)
|
| 237 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
def replace_video_audio(video_path: str, new_audio_path: str) -> str:
|
| 239 |
"""
|
| 240 |
Replaces a video's audio with new translated audio.
|
|
@@ -256,37 +260,48 @@ def replace_video_audio(video_path: str, new_audio_path: str) -> str:
|
|
| 256 |
if not isinstance(video_path, str):
|
| 257 |
raise ValueError(f"video_path must be a string, got {type(video_path)}")
|
| 258 |
|
| 259 |
-
# Load video
|
| 260 |
video = VideoFileClip(video_path)
|
| 261 |
-
|
| 262 |
-
# Load new audio
|
| 263 |
new_audio = AudioFileClip(new_audio_path)
|
| 264 |
|
| 265 |
# Extend video if new audio is longer
|
| 266 |
if new_audio.duration > video.duration:
|
| 267 |
-
|
| 268 |
-
|
| 269 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
|
| 271 |
video = concatenate_videoclips([video, freeze_frame])
|
| 272 |
|
| 273 |
-
# Set new audio
|
| 274 |
video = video.set_audio(new_audio)
|
| 275 |
-
|
| 276 |
-
# Create a temp file
|
| 277 |
temp_video = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
|
| 278 |
-
|
| 279 |
-
# Save
|
| 280 |
video.write_videofile(
|
| 281 |
temp_video.name,
|
| 282 |
codec="libx264",
|
| 283 |
audio_codec="aac",
|
| 284 |
-
fps=video.fps,
|
| 285 |
-
preset="medium"
|
| 286 |
)
|
| 287 |
|
| 288 |
-
|
| 289 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
|
| 291 |
def clean_previous_video_input():
|
| 292 |
return gr.update(value=None)
|
|
|
|
| 235 |
else:
|
| 236 |
return gr.update(value=temp_output_path, visible=True), gr.update(visible=False)
|
| 237 |
|
| 238 |
+
import tempfile
|
| 239 |
+
import gradio as gr
|
| 240 |
+
from moviepy.editor import VideoFileClip, AudioFileClip, ImageClip, concatenate_videoclips
|
| 241 |
+
|
| 242 |
def replace_video_audio(video_path: str, new_audio_path: str) -> str:
|
| 243 |
"""
|
| 244 |
Replaces a video's audio with new translated audio.
|
|
|
|
| 260 |
if not isinstance(video_path, str):
|
| 261 |
raise ValueError(f"video_path must be a string, got {type(video_path)}")
|
| 262 |
|
| 263 |
+
# Load video and audio
|
| 264 |
video = VideoFileClip(video_path)
|
|
|
|
|
|
|
| 265 |
new_audio = AudioFileClip(new_audio_path)
|
| 266 |
|
| 267 |
# Extend video if new audio is longer
|
| 268 |
if new_audio.duration > video.duration:
|
| 269 |
+
# Safely extract last frame
|
| 270 |
+
print("Extending video to match longer audio...")
|
| 271 |
+
last_frame = None
|
| 272 |
+
for frame in video.iter_frames(): # Iterates through all frames
|
| 273 |
+
last_frame = frame
|
| 274 |
+
|
| 275 |
+
if last_frame is None:
|
| 276 |
+
raise RuntimeError("Failed to extract last frame from video.")
|
| 277 |
+
|
| 278 |
+
freeze_duration = new_audio.duration - video.duration
|
| 279 |
+
freeze_frame = ImageClip(last_frame).set_duration(freeze_duration).set_fps(video.fps)
|
| 280 |
|
| 281 |
video = concatenate_videoclips([video, freeze_frame])
|
| 282 |
|
| 283 |
+
# Set the new audio track
|
| 284 |
video = video.set_audio(new_audio)
|
| 285 |
+
|
| 286 |
+
# Create a temp file for output
|
| 287 |
temp_video = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
|
| 288 |
+
|
| 289 |
+
# Save the final video
|
| 290 |
video.write_videofile(
|
| 291 |
temp_video.name,
|
| 292 |
codec="libx264",
|
| 293 |
audio_codec="aac",
|
| 294 |
+
fps=video.fps,
|
| 295 |
+
preset="medium"
|
| 296 |
)
|
| 297 |
|
| 298 |
+
# Clean up resources
|
| 299 |
+
video.close()
|
| 300 |
+
new_audio.close()
|
| 301 |
+
|
| 302 |
+
# Return path to new video
|
| 303 |
+
return gr.update(value=temp_video.name, visible=True)
|
| 304 |
+
|
| 305 |
|
| 306 |
def clean_previous_video_input():
|
| 307 |
return gr.update(value=None)
|