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)