im commited on
Commit
d5efeb7
·
1 Parent(s): 153521d

added files

Browse files
Files changed (3) hide show
  1. .streamlit/config.toml +3 -0
  2. app.py +115 -0
  3. requirements.txt +2 -0
.streamlit/config.toml ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ [theme]
2
+ base="light"
3
+ font="sans serif"
app.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from moviepy.editor import VideoFileClip, VideoClip
3
+ from moviepy.video.fx.all import crop
4
+ import tempfile
5
+ import os
6
+ import numpy as np
7
+ from PIL import Image, ImageDraw
8
+ import hashlib
9
+
10
+ # Fix for PIL.Image.ANTIALIAS deprecation
11
+ if not hasattr(Image, 'ANTIALIAS'):
12
+ Image.ANTIALIAS = Image.LANCZOS
13
+
14
+ # Function to create a circular mask
15
+ def create_circular_mask(size):
16
+ # Create a square image with a black background
17
+ img = Image.new('L', (size, size), 0)
18
+ # Create a white circle in the middle
19
+ draw = ImageDraw.Draw(img)
20
+ draw.ellipse((0, 0, size, size), fill=255)
21
+ # Convert the image to a numpy array
22
+ mask = np.array(img) / 255.0 # Normalize to [0, 1] range
23
+ return mask
24
+
25
+ def compute_file_hash(file):
26
+ hash_md5 = hashlib.md5()
27
+ for chunk in file:
28
+ hash_md5.update(chunk)
29
+ file.seek(0) # Reset file pointer after reading
30
+ return hash_md5.hexdigest()
31
+
32
+ # Function to process the video with audio and progress logging
33
+ @st.cache_data(hash_funcs={str: lambda _: None}) # Ignore `input_path` by setting its hash to None
34
+ def process_video(input_path, file_hash):
35
+ # Load the video file
36
+ input_video = VideoFileClip(input_path)
37
+ w, h = input_video.size
38
+ circle_size = 360
39
+ aspect_ratio = w / h
40
+
41
+ # Resize the video while maintaining aspect ratio
42
+ if w > h:
43
+ new_w = int(circle_size * aspect_ratio)
44
+ new_h = circle_size
45
+ else:
46
+ new_w = circle_size
47
+ new_h = int(circle_size / aspect_ratio)
48
+
49
+ # Resize and crop the video to a square
50
+ resized_video = input_video.resize((new_w, new_h))
51
+ square_video = crop(
52
+ resized_video,
53
+ x_center=new_w / 2,
54
+ y_center=new_h / 2,
55
+ width=circle_size,
56
+ height=circle_size
57
+ )
58
+
59
+ # Create a circular mask
60
+ mask_array = create_circular_mask(circle_size)
61
+
62
+ # Apply the circular mask to each frame
63
+ def apply_mask(get_frame, t):
64
+ frame = get_frame(t)
65
+ alpha = mask_array[..., np.newaxis] # Add axis for channels
66
+ frame = frame * alpha + 255 * (1 - alpha) # Assuming white background
67
+ return frame.astype('uint8')
68
+
69
+ circular_video = square_video.fl(apply_mask)
70
+
71
+ # Add audio back to the video
72
+ circular_video = circular_video.set_audio(input_video.audio)
73
+
74
+ # Save output to a temporary file with progress logging
75
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
76
+ circular_video.write_videofile(
77
+ temp_file.name,
78
+ codec="libx264",
79
+ audio_codec="aac",
80
+ temp_audiofile=tempfile.NamedTemporaryFile(suffix=".m4a").name,
81
+ remove_temp=True,
82
+ )
83
+ return temp_file.name
84
+
85
+ # Streamlit UI
86
+ st.title("Circular Video Cropper with Progress")
87
+ st.write("Upload a video, and the app will crop it into a circular format with visible progress.")
88
+
89
+ # Upload file
90
+ uploaded_file = st.file_uploader("Choose a video file", type=["mp4", "mov", "avi", "mkv"])
91
+
92
+ if uploaded_file:
93
+
94
+ file_hash = compute_file_hash(uploaded_file)
95
+ # Save uploaded file to a temporary location
96
+ temp_input_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
97
+ temp_input_file.write(uploaded_file.read())
98
+ temp_input_file.close()
99
+
100
+ input_video = VideoFileClip(temp_input_file.name)
101
+ total_duration = input_video.duration
102
+
103
+ output_path = process_video(temp_input_file.name, file_hash)
104
+
105
+ # Display success and download button
106
+ st.success("Video processed successfully!")
107
+ with open(output_path, "rb") as file:
108
+ st.download_button(
109
+ label="Download Circular Video",
110
+ data=file,
111
+ file_name="circular_video.mp4",
112
+ mime="video/mp4"
113
+ )
114
+
115
+ os.remove(temp_input_file.name)
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ streamlit==1.39.0
2
+ moviepy==1.0.3