make_movies / app.py
rockerritesh's picture
Update app.py
d69b229 verified
import streamlit as st
import os
import tempfile
import numpy as np
import cv2
from PIL import Image
import subprocess
import random
import time
# Set page config
st.set_page_config(page_title="Audio + Image to Video Converter", layout="wide")
def add_snow_effect(frame, density=0.01):
"""Add snow effect to a frame"""
h, w = frame.shape[:2]
snow_points = np.random.rand(int(h*w*density), 2)
snow_points[:, 0] *= h
snow_points[:, 1] *= w
for y, x in snow_points.astype(int):
if 0 <= y < h and 0 <= x < w:
frame[y, x] = [255, 255, 255] # White snow
return frame
def add_heart_effect(frame, density=0.002):
"""Add heart effect to a frame"""
h, w = frame.shape[:2]
heart_points = np.random.rand(int(h*w*density), 2)
heart_points[:, 0] *= h
heart_points[:, 1] *= w
heart_colors = [
[255, 0, 0], # Red
[255, 20, 147], # Pink
[255, 105, 180] # Hot Pink
]
for y, x in heart_points.astype(int):
if 0 <= y < h and 0 <= x < w:
color = random.choice(heart_colors)
cv2.drawMarker(frame, (int(x), int(y)), color,
markerType=cv2.MARKER_STAR, markerSize=10, thickness=2)
return frame
def add_wave_effect(frame, time_val, amplitude=20, frequency=0.1):
"""Add wave effect to a frame"""
h, w = frame.shape[:2]
for x in range(w):
offset = int(amplitude * np.sin(frequency * x + time_val))
for y in range(h):
src_y = y + offset
if 0 <= src_y < h:
frame[y, x] = frame[src_y, x]
return frame
def add_sparkle_effect(frame, density=0.001):
"""Add sparkle effect to a frame"""
h, w = frame.shape[:2]
sparkle_points = np.random.rand(int(h*w*density), 2)
sparkle_points[:, 0] *= h
sparkle_points[:, 1] *= w
sparkle_colors = [
[255, 215, 0], # Gold
[255, 255, 255], # White
[173, 216, 230] # Light Blue
]
for y, x in sparkle_points.astype(int):
if 0 <= y < h and 0 <= x < w:
size = random.randint(1, 3)
color = random.choice(sparkle_colors)
cv2.circle(frame, (int(x), int(y)), size, color, -1)
return frame
def get_audio_duration(audio_path):
"""Get the duration of an audio file using ffprobe"""
cmd = [
'ffprobe',
'-v', 'error',
'-show_entries', 'format=duration',
'-of', 'default=noprint_wrappers=1:nokey=1',
audio_path
]
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
return float(result.stdout.strip())
def create_video(image_path, audio_path, effect_type, output_path, fps=24):
"""Create a video from an image and audio with the selected effect"""
# Get audio duration
try:
duration = get_audio_duration(audio_path)
except Exception as e:
st.error(f"Error getting audio duration: {e}")
# Fallback to a default duration if ffprobe fails
duration = 30.0
# Load image
img = cv2.imread(image_path)
h, w = img.shape[:2]
# Define output video parameters
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
temp_video_path = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False).name
out = cv2.VideoWriter(temp_video_path, fourcc, fps, (w, h))
# Calculate total frames
total_frames = int(duration * fps)
progress_bar = st.progress(0)
# Generate video frames with effect
for i in range(total_frames):
progress = i / total_frames
progress_bar.progress(progress)
# Create a copy of the original image
frame = img.copy()
time_val = i / fps
# Apply selected effect
if effect_type == 'Snow':
frame = add_snow_effect(frame)
elif effect_type == 'Hearts':
frame = add_heart_effect(frame)
elif effect_type == 'Waves':
frame = add_wave_effect(frame, time_val)
elif effect_type == 'Sparkles':
frame = add_sparkle_effect(frame)
elif effect_type == 'Random':
effect = random.choice(['Snow', 'Hearts', 'Waves', 'Sparkles'])
if effect == 'Snow':
frame = add_snow_effect(frame)
elif effect == 'Hearts':
frame = add_heart_effect(frame)
elif effect == 'Waves':
frame = add_wave_effect(frame, time_val)
elif effect == 'Sparkles':
frame = add_sparkle_effect(frame)
# Write the frame
out.write(frame)
# Release the video writer
out.release()
# Combine the silent video with audio using ffmpeg directly
cmd = [
'ffmpeg',
'-i', temp_video_path, # Input video file
'-i', audio_path, # Input audio file
'-map', '0:v', # Use video from first input
'-map', '1:a', # Use audio from second input
'-c:v', 'copy', # Copy the video codec
'-c:a', 'aac', # Use AAC for audio
'-shortest', # End when the shortest input ends
output_path # Output file
]
# Run ffmpeg command
subprocess.run(cmd, check=True)
# Clean up temporary file
os.remove(temp_video_path)
progress_bar.progress(1.0)
return output_path
def main():
st.title("🎵 Audio + Image to Video Creator 🖼️")
st.markdown("""
Upload an audio file and an image to create a video!
The image will be static throughout the video, and you can add visual effects.
""")
# Sidebar for effects selection
st.sidebar.title("Effect Options")
effect_type = st.sidebar.selectbox(
"Choose Visual Effect",
["None", "Snow", "Hearts", "Waves", "Sparkles", "Random"]
)
# File uploaders
col1, col2 = st.columns(2)
with col1:
st.subheader("Upload Audio File")
audio_file = st.file_uploader("Choose an audio file", type=["mp3", "wav", "ogg"])
if audio_file is not None:
# Save the audio file temporarily
audio_path = tempfile.NamedTemporaryFile(delete=False, suffix='.mp3').name
with open(audio_path, "wb") as f:
f.write(audio_file.getbuffer())
st.audio(audio_file)
with col2:
st.subheader("Upload Image")
image_file = st.file_uploader("Choose an image", type=["jpg", "jpeg", "png"])
if image_file is not None:
# Save the image file temporarily
image_path = tempfile.NamedTemporaryFile(delete=False, suffix='.jpg').name
with open(image_path, "wb") as f:
f.write(image_file.getbuffer())
st.image(image_file, caption="Uploaded Image", use_column_width=True)
# Generate video when both files are uploaded
if st.button("Create Video", disabled=(audio_file is None or image_file is None)):
if audio_file is not None and image_file is not None:
st.subheader("Creating Video...")
# Create a temporary output file
output_path = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4').name
with st.spinner("Processing..."):
try:
video_path = create_video(image_path, audio_path, effect_type, output_path)
# Display the output video
st.subheader("Generated Video")
st.video(video_path)
# Provide download link
with open(video_path, "rb") as file:
btn = st.download_button(
label="Download Video",
data=file,
file_name="output_video.mp4",
mime="video/mp4"
)
except Exception as e:
st.error(f"Error creating video: {e}")
finally:
# Clean up temporary files
if 'audio_path' in locals():
os.remove(audio_path)
if 'image_path' in locals():
os.remove(image_path)
if 'output_path' in locals() and os.path.exists(output_path):
os.remove(output_path)
if __name__ == "__main__":
main()