Spaces:
Running
Running
import gradio as gr | |
import subprocess | |
import os | |
import uuid | |
# Carpeta temporal para guardar los videos generados | |
TEMP_DIR = "temp_videos" | |
os.makedirs(TEMP_DIR, exist_ok=True) | |
def get_audio_duration(audio_path): | |
"""Obtiene duración del audio en segundos usando ffprobe""" | |
try: | |
result = subprocess.run([ | |
"ffprobe", "-v", "error", "-show_entries", | |
"format=duration", "-of", | |
"default=noprint_wrappers=1:nokey=1", audio_path | |
], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) | |
return float(result.stdout.strip()) | |
except: | |
return None | |
def generate_video(audio_path, image_path): | |
if not os.path.isfile(audio_path) or not os.path.isfile(image_path): | |
return "❌ Missing or invalid input files." | |
duration = get_audio_duration(audio_path) | |
if not duration: | |
return "❌ Could not get audio duration. Check your audio file." | |
output_filename = os.path.join("temp_videos", f"output_{uuid.uuid4().hex[:8]}.mp4") | |
try: | |
cmd = [ | |
"ffmpeg", "-y", | |
"-loop", "1", "-framerate", "1", "-i", image_path, | |
"-i", audio_path, | |
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2", # 👈 FIX AQUI | |
"-c:v", "libx264", "-preset", "ultrafast", "-tune", "stillimage", | |
"-c:a", "aac", "-b:a", "192k", | |
"-t", str(duration), | |
"-pix_fmt", "yuv420p", "-r", "1", | |
output_filename | |
] | |
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) | |
if os.path.exists(output_filename) and os.path.getsize(output_filename) > 0: | |
return output_filename | |
else: | |
print("FFmpeg ERROR:", result.stderr) | |
return "❌ Something went wrong while generating the video." | |
except Exception as e: | |
return f"⚠️ Error: {str(e)}" | |
# Interfaz Gradio | |
with gr.Blocks(theme="Taithrah/Minimal") as app: | |
gr.Markdown("# 🎶 Audio to Video Tool\nUpload an audio file and an image to generate a simple MP4 video (like TunesToTube)") | |
with gr.Row(): | |
audio = gr.Audio(label="🎧 Upload your audio file", type="filepath") | |
image = gr.Image(label="🖼️ Upload your image", type="filepath") | |
submit = gr.Button("🚀 Generate Video") | |
output = gr.Video(label="🎬 Your Video") | |
def handle_generate(audio_path, image_path): | |
result = generate_video(audio_path, image_path) | |
# Si es una string con error, la mandamos como mensaje, si es ruta, se muestra el video | |
if result.endswith(".mp4") and os.path.exists(result): | |
return result | |
else: | |
return gr.update(value=None, visible=False), gr.update(value=result, visible=True) | |
submit.click(fn=handle_generate, inputs=[audio, image], outputs=output) | |
app.launch() |