Aud2Vid / app.py
PlayerBPlaytime's picture
Update app.py
7b346cc verified
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()