RoundVideo / app.py
im
added files
d5efeb7
raw
history blame
3.72 kB
import streamlit as st
from moviepy.editor import VideoFileClip, VideoClip
from moviepy.video.fx.all import crop
import tempfile
import os
import numpy as np
from PIL import Image, ImageDraw
import hashlib
# Fix for PIL.Image.ANTIALIAS deprecation
if not hasattr(Image, 'ANTIALIAS'):
Image.ANTIALIAS = Image.LANCZOS
# Function to create a circular mask
def create_circular_mask(size):
# Create a square image with a black background
img = Image.new('L', (size, size), 0)
# Create a white circle in the middle
draw = ImageDraw.Draw(img)
draw.ellipse((0, 0, size, size), fill=255)
# Convert the image to a numpy array
mask = np.array(img) / 255.0 # Normalize to [0, 1] range
return mask
def compute_file_hash(file):
hash_md5 = hashlib.md5()
for chunk in file:
hash_md5.update(chunk)
file.seek(0) # Reset file pointer after reading
return hash_md5.hexdigest()
# Function to process the video with audio and progress logging
@st.cache_data(hash_funcs={str: lambda _: None}) # Ignore `input_path` by setting its hash to None
def process_video(input_path, file_hash):
# Load the video file
input_video = VideoFileClip(input_path)
w, h = input_video.size
circle_size = 360
aspect_ratio = w / h
# Resize the video while maintaining aspect ratio
if w > h:
new_w = int(circle_size * aspect_ratio)
new_h = circle_size
else:
new_w = circle_size
new_h = int(circle_size / aspect_ratio)
# Resize and crop the video to a square
resized_video = input_video.resize((new_w, new_h))
square_video = crop(
resized_video,
x_center=new_w / 2,
y_center=new_h / 2,
width=circle_size,
height=circle_size
)
# Create a circular mask
mask_array = create_circular_mask(circle_size)
# Apply the circular mask to each frame
def apply_mask(get_frame, t):
frame = get_frame(t)
alpha = mask_array[..., np.newaxis] # Add axis for channels
frame = frame * alpha + 255 * (1 - alpha) # Assuming white background
return frame.astype('uint8')
circular_video = square_video.fl(apply_mask)
# Add audio back to the video
circular_video = circular_video.set_audio(input_video.audio)
# Save output to a temporary file with progress logging
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
circular_video.write_videofile(
temp_file.name,
codec="libx264",
audio_codec="aac",
temp_audiofile=tempfile.NamedTemporaryFile(suffix=".m4a").name,
remove_temp=True,
)
return temp_file.name
# Streamlit UI
st.title("Circular Video Cropper with Progress")
st.write("Upload a video, and the app will crop it into a circular format with visible progress.")
# Upload file
uploaded_file = st.file_uploader("Choose a video file", type=["mp4", "mov", "avi", "mkv"])
if uploaded_file:
file_hash = compute_file_hash(uploaded_file)
# Save uploaded file to a temporary location
temp_input_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
temp_input_file.write(uploaded_file.read())
temp_input_file.close()
input_video = VideoFileClip(temp_input_file.name)
total_duration = input_video.duration
output_path = process_video(temp_input_file.name, file_hash)
# Display success and download button
st.success("Video processed successfully!")
with open(output_path, "rb") as file:
st.download_button(
label="Download Circular Video",
data=file,
file_name="circular_video.mp4",
mime="video/mp4"
)
os.remove(temp_input_file.name)