Spaces:
Sleeping
Sleeping
File size: 3,724 Bytes
d5efeb7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
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)
|