Spaces:
Sleeping
Sleeping
Upload 41 files
Browse files- app.py +64 -0
- app_basic.py +29 -0
- dev.ipynb +231 -0
- output.mp4 +0 -0
- requirements.txt +4 -0
- trim_silence.py +198 -0
- trimmed_clips/0_cut.mp4 +0 -0
- trimmed_clips/100000_cut.mp4 +0 -0
- trimmed_clips/1000_cut.mp4 +0 -0
- trimmed_clips/100_cut.mp4 +0 -0
- trimmed_clips/10_cut.mp4 +0 -0
- trimmed_clips/11_cut.mp4 +0 -0
- trimmed_clips/12_cut.mp4 +0 -0
- trimmed_clips/13_cut.mp4 +0 -0
- trimmed_clips/14_cut.mp4 +0 -0
- trimmed_clips/15_cut.mp4 +0 -0
- trimmed_clips/16_cut.mp4 +0 -0
- trimmed_clips/17_cut.mp4 +0 -0
- trimmed_clips/18_cut.mp4 +0 -0
- trimmed_clips/19_cut.mp4 +0 -0
- trimmed_clips/1_cut.mp4 +0 -0
- trimmed_clips/20_cut.mp4 +0 -0
- trimmed_clips/2_cut.mp4 +0 -0
- trimmed_clips/30_cut.mp4 +0 -0
- trimmed_clips/3_cut.mp4 +0 -0
- trimmed_clips/40_cut.mp4 +0 -0
- trimmed_clips/4_cut.mp4 +0 -0
- trimmed_clips/50_cut.mp4 +0 -0
- trimmed_clips/5_cut.mp4 +0 -0
- trimmed_clips/60_cut.mp4 +0 -0
- trimmed_clips/6_cut.mp4 +0 -0
- trimmed_clips/70_cut.mp4 +0 -0
- trimmed_clips/7_cut.mp4 +0 -0
- trimmed_clips/80_cut.mp4 +0 -0
- trimmed_clips/8_cut.mp4 +0 -0
- trimmed_clips/90_cut.mp4 +0 -0
- trimmed_clips/9_cut.mp4 +0 -0
- trimmed_clips/Conclusion_cut.mp4 +0 -0
- trimmed_clips/Intro_cut.mp4 +0 -0
- utils.py +157 -0
app.py
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from utils import *
|
3 |
+
|
4 |
+
st.set_page_config(
|
5 |
+
page_title="Number to Video",
|
6 |
+
page_icon="🎥",
|
7 |
+
initial_sidebar_state="auto",
|
8 |
+
)
|
9 |
+
|
10 |
+
# Input number
|
11 |
+
number = st.text_input("Enter a number between 1 and 9999999", "24")
|
12 |
+
number = int(number)
|
13 |
+
|
14 |
+
if number:
|
15 |
+
col1, col2 = st.columns(2)
|
16 |
+
|
17 |
+
with col1:
|
18 |
+
with st.container(border=True):
|
19 |
+
st.subheader("Settings")
|
20 |
+
st.divider()
|
21 |
+
|
22 |
+
# Generate clip sequence based on the number
|
23 |
+
clips = generate_clip_sequence(number)
|
24 |
+
if clips:
|
25 |
+
st.write("Generated Clips Sequence:")
|
26 |
+
for i, clip in enumerate(clips):
|
27 |
+
st.write(f"Clip {i + 1}: {clip}")
|
28 |
+
submit = st.button("Create Video", use_container_width=True)
|
29 |
+
|
30 |
+
if clips:
|
31 |
+
with st.sidebar:
|
32 |
+
st.title("Advanced Settings")
|
33 |
+
trim_settings = []
|
34 |
+
for i, clip in enumerate(clips):
|
35 |
+
with st.container(border=True):
|
36 |
+
st.write(f"Adjust settings for {clip}:")
|
37 |
+
length = get_clip_duration(clip)
|
38 |
+
default_trim_start = 0.10
|
39 |
+
default_trim_end = length - 0.10
|
40 |
+
# trim_bounds = st.slider(
|
41 |
+
# f"Trim bounds for {clip}",
|
42 |
+
# 0.0, length,
|
43 |
+
# (default_trim_start, default_trim_end),
|
44 |
+
# 0.001,
|
45 |
+
# key=f"bounds_{i}"
|
46 |
+
# )
|
47 |
+
# trim_bounds = tuple([round(b, 2) for b in trim_bounds])
|
48 |
+
# print(trim_bounds)
|
49 |
+
# trim_settings.append(trim_bounds)
|
50 |
+
|
51 |
+
trim_start = st.slider(f"Trim start for {clip}", 0.0, length, 0.10, 0.01, key=f"start_{i}")
|
52 |
+
trim_end = st.slider(f"Trim end for {clip}", 0.0, length, 0.10, 0.01, key=f"end_{i}")
|
53 |
+
trim_settings.append((trim_start, trim_end))
|
54 |
+
print(trim_settings)
|
55 |
+
|
56 |
+
with col2:
|
57 |
+
with st.container(border=True):
|
58 |
+
st.subheader("Output")
|
59 |
+
output_file = "output.mp4"
|
60 |
+
if submit:
|
61 |
+
pass
|
62 |
+
# Create the video with individual clip settings
|
63 |
+
create_advanced_video(number, trim_settings, output_file)
|
64 |
+
st.video(output_file, autoplay=True)
|
app_basic.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from utils import *
|
3 |
+
|
4 |
+
st.set_page_config(
|
5 |
+
page_title="Number to Video - Advanced Settings",
|
6 |
+
page_icon="🎥",
|
7 |
+
initial_sidebar_state="collapsed",
|
8 |
+
)
|
9 |
+
|
10 |
+
col1, col2 = st.columns(2)
|
11 |
+
|
12 |
+
with col1:
|
13 |
+
with st.container(border=True):
|
14 |
+
st.subheader("Settings")
|
15 |
+
st.divider()
|
16 |
+
trim_start = st.slider("Trim start", 0.0, 1.0, 0.10, 0.01)
|
17 |
+
trim_end = st.slider("Trim end", 0.0, 1.0, 0.10, 0.01)
|
18 |
+
number = st.text_input("Enter a number between 1 and 9999999", "123")
|
19 |
+
number = int(number)
|
20 |
+
clips = generate_clip_sequence(number)
|
21 |
+
submit = st.button("Create Video", use_container_width=True)
|
22 |
+
|
23 |
+
|
24 |
+
with col2:
|
25 |
+
with st.container(border=True):
|
26 |
+
output_file = "output.mp4"
|
27 |
+
if submit:
|
28 |
+
create_video(number, trim_start, trim_end, output_file)
|
29 |
+
st.video(output_file, autoplay=True)
|
dev.ipynb
ADDED
@@ -0,0 +1,231 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 29,
|
6 |
+
"metadata": {},
|
7 |
+
"outputs": [
|
8 |
+
{
|
9 |
+
"name": "stdout",
|
10 |
+
"output_type": "stream",
|
11 |
+
"text": [
|
12 |
+
"Clips: ['1.mp4', '1.mp4']\n"
|
13 |
+
]
|
14 |
+
},
|
15 |
+
{
|
16 |
+
"data": {
|
17 |
+
"text/plain": [
|
18 |
+
"['1.mp4', '1.mp4']"
|
19 |
+
]
|
20 |
+
},
|
21 |
+
"execution_count": 29,
|
22 |
+
"metadata": {},
|
23 |
+
"output_type": "execute_result"
|
24 |
+
}
|
25 |
+
],
|
26 |
+
"source": [
|
27 |
+
"files = {\n",
|
28 |
+
" 1: \"1.mp4\", 2: \"2.mp4\", 3: \"3.mp4\", 4: \"4.mp4\", 5: \"5.mp4\",\n",
|
29 |
+
" 6: \"6.mp4\", 7: \"7.mp4\", 8: \"8.mp4\", 9: \"9.mp4\",\n",
|
30 |
+
" 10: \"10.mp4\", 11: \"11.mp4\", 12: \"12.mp4\", 13: \"13.mp4\", 14: \"14.mp4\",\n",
|
31 |
+
" 15: \"15.mp4\", 16: \"16.mp4\", 17: \"17.mp4\", 18: \"18.mp4\", 19: \"19.mp4\",\n",
|
32 |
+
" 20: \"20.mp4\", 30: \"30.mp4\", 40: \"40.mp4\", 50: \"50.mp4\", \n",
|
33 |
+
" 60: \"60.mp4\", 70: \"70.mp4\", 80: \"80.mp4\", 90: \"90.mp4\",\n",
|
34 |
+
" 100: \"100.mp4\", 1000: \"1000.mp4\",\n",
|
35 |
+
" 100000: \"100000.mp4\"\n",
|
36 |
+
"}\n",
|
37 |
+
"\n",
|
38 |
+
"def get_clips(number):\n",
|
39 |
+
" num_digits = len(str(number))\n",
|
40 |
+
" place_values = []\n",
|
41 |
+
" place = 1\n",
|
42 |
+
"\n",
|
43 |
+
" # Split number into place values\n",
|
44 |
+
" while number > 0:\n",
|
45 |
+
" digit = number % 10\n",
|
46 |
+
" if digit > 0:\n",
|
47 |
+
" place_values.append((digit, place))\n",
|
48 |
+
" number //= 10\n",
|
49 |
+
" place *= 10\n",
|
50 |
+
" \n",
|
51 |
+
" place_values.reverse() # To process from the highest place value\n",
|
52 |
+
" clips = []\n",
|
53 |
+
" i = 0\n",
|
54 |
+
"\n",
|
55 |
+
" while i < len(place_values):\n",
|
56 |
+
" digit, place = place_values[i]\n",
|
57 |
+
"\n",
|
58 |
+
" # Handle cases for 1-20 at specific positions\n",
|
59 |
+
" if place == 1 and i > 0 and place_values[i - 1][1] == 10: # Check for numbers ending in 1-20\n",
|
60 |
+
" combined = place_values[i - 1][0] * 10 + digit\n",
|
61 |
+
" if 1 <= combined <= 20:\n",
|
62 |
+
" clips.pop() # Remove the previous 10's place clip\n",
|
63 |
+
" clips.append(files[combined])\n",
|
64 |
+
" i += 1\n",
|
65 |
+
" continue\n",
|
66 |
+
" \n",
|
67 |
+
" if place == 10 and digit * 10 <= 20: # Numbers between 1-20 at higher positions\n",
|
68 |
+
" if i + 1 < len(place_values) and place_values[i + 1][1] == 1:\n",
|
69 |
+
" combined = digit * 10 + place_values[i + 1][0]\n",
|
70 |
+
" if 1 <= combined <= 20:\n",
|
71 |
+
" clips.append(files[combined])\n",
|
72 |
+
" i += 2\n",
|
73 |
+
" continue\n",
|
74 |
+
"\n",
|
75 |
+
" # Add individual clips\n",
|
76 |
+
" if digit in files:\n",
|
77 |
+
" clips.append(files[digit])\n",
|
78 |
+
" if digit * place in files:\n",
|
79 |
+
" clips.append(files[digit * place])\n",
|
80 |
+
"\n",
|
81 |
+
" i += 1\n",
|
82 |
+
"\n",
|
83 |
+
" # Handle 10,000 and 10,00,000 special cases\n",
|
84 |
+
" if len(place_values) % 2 == 1 and place_values[0][1] in [10000, 100000]:\n",
|
85 |
+
" first_digit = place_values[0][0]\n",
|
86 |
+
" if 1 <= first_digit <= 20:\n",
|
87 |
+
" clips.insert(0, files[first_digit])\n",
|
88 |
+
" elif first_digit * 10 in files:\n",
|
89 |
+
" clips.insert(0, files[first_digit * 10])\n",
|
90 |
+
" place_values = place_values[1:]\n",
|
91 |
+
"\n",
|
92 |
+
" print(\"Clips:\", clips)\n",
|
93 |
+
" return clips\n",
|
94 |
+
"\n",
|
95 |
+
"# Example usage\n",
|
96 |
+
"number = int(input(\"Enter a number: \"))\n",
|
97 |
+
"get_clips(number)\n"
|
98 |
+
]
|
99 |
+
},
|
100 |
+
{
|
101 |
+
"cell_type": "code",
|
102 |
+
"execution_count": 33,
|
103 |
+
"metadata": {},
|
104 |
+
"outputs": [
|
105 |
+
{
|
106 |
+
"name": "stdout",
|
107 |
+
"output_type": "stream",
|
108 |
+
"text": [
|
109 |
+
"99: ['90.mp4', '9.mp4']\n",
|
110 |
+
"111: ['1.mp4', '100.mp4', '11.mp4']\n",
|
111 |
+
"256: ['2.mp4', '100.mp4', '50.mp4', '6.mp4']\n",
|
112 |
+
"1000: ['1.mp4', '1000.mp4']\n",
|
113 |
+
"1011: ['1.mp4', '1000.mp4', '11.mp4']\n",
|
114 |
+
"9999: ['9.mp4', '1000.mp4', '9.mp4', '100.mp4', '90.mp4', '9.mp4']\n",
|
115 |
+
"10000: ['10.mp4', '1000.mp4']\n",
|
116 |
+
"24256: ['20.mp4', '4.mp4', '1000.mp4', '2.mp4', '100.mp4', '50.mp4', '6.mp4']\n",
|
117 |
+
"22: ['20.mp4', '2.mp4']\n",
|
118 |
+
"19: ['19.mp4']\n",
|
119 |
+
"4: ['4.mp4']\n"
|
120 |
+
]
|
121 |
+
}
|
122 |
+
],
|
123 |
+
"source": [
|
124 |
+
"files = {\n",
|
125 |
+
" 1: \"1.mp4\", 2: \"2.mp4\", 3: \"3.mp4\", 4: \"4.mp4\", 5: \"5.mp4\",\n",
|
126 |
+
" 6: \"6.mp4\", 7: \"7.mp4\", 8: \"8.mp4\", 9: \"9.mp4\",\n",
|
127 |
+
" 10: \"10.mp4\", 11: \"11.mp4\", 12: \"12.mp4\", 13: \"13.mp4\", 14: \"14.mp4\",\n",
|
128 |
+
" 15: \"15.mp4\", 16: \"16.mp4\", 17: \"17.mp4\", 18: \"18.mp4\", 19: \"19.mp4\",\n",
|
129 |
+
" 20: \"20.mp4\", 30: \"30.mp4\", 40: \"40.mp4\", 50: \"50.mp4\",\n",
|
130 |
+
" 60: \"60.mp4\", 70: \"70.mp4\", 80: \"80.mp4\", 90: \"90.mp4\",\n",
|
131 |
+
" 100: \"100.mp4\", 1000: \"1000.mp4\",\n",
|
132 |
+
" 100000: \"100000.mp4\"\n",
|
133 |
+
"}\n",
|
134 |
+
"\n",
|
135 |
+
"def number_to_clips(n):\n",
|
136 |
+
" components = []\n",
|
137 |
+
" if n >= 100000:\n",
|
138 |
+
" lakh = n // 100000\n",
|
139 |
+
" if lakh > 0:\n",
|
140 |
+
" components.append(lakh)\n",
|
141 |
+
" components.append(100000)\n",
|
142 |
+
" n %= 100000\n",
|
143 |
+
" if n >= 1000:\n",
|
144 |
+
" thousand = n // 1000\n",
|
145 |
+
" if thousand > 0:\n",
|
146 |
+
" components.append(thousand)\n",
|
147 |
+
" components.append(1000)\n",
|
148 |
+
" n %= 1000\n",
|
149 |
+
" if n >= 100:\n",
|
150 |
+
" hundred = n // 100\n",
|
151 |
+
" if hundred > 0:\n",
|
152 |
+
" components.append(hundred)\n",
|
153 |
+
" components.append(100)\n",
|
154 |
+
" n %= 100\n",
|
155 |
+
" if n > 20:\n",
|
156 |
+
" tens = (n // 10) * 10\n",
|
157 |
+
" if tens > 0:\n",
|
158 |
+
" components.append(tens)\n",
|
159 |
+
" n %= 10\n",
|
160 |
+
" if n > 0:\n",
|
161 |
+
" components.append(n)\n",
|
162 |
+
" return components\n",
|
163 |
+
"\n",
|
164 |
+
"def generate_clip_sequence(n):\n",
|
165 |
+
" components = number_to_clips(n)\n",
|
166 |
+
" clip_sequence = []\n",
|
167 |
+
" for component in components:\n",
|
168 |
+
" if component in files:\n",
|
169 |
+
" clip_sequence.append(files[component])\n",
|
170 |
+
" else:\n",
|
171 |
+
" # Break down further if component is not in files\n",
|
172 |
+
" sub_components = number_to_clips(component)\n",
|
173 |
+
" clip_sequence.extend([files[sub] for sub in sub_components])\n",
|
174 |
+
" return clip_sequence\n",
|
175 |
+
"\n",
|
176 |
+
"# Example usage\n",
|
177 |
+
"examples = [99, 111, 256, 1000, 1011, 9999, 10000, 24256, 22, 19, 4]\n",
|
178 |
+
"for example in examples:\n",
|
179 |
+
" print(f\"{example}: {generate_clip_sequence(example)}\")\n"
|
180 |
+
]
|
181 |
+
},
|
182 |
+
{
|
183 |
+
"cell_type": "code",
|
184 |
+
"execution_count": 9,
|
185 |
+
"metadata": {},
|
186 |
+
"outputs": [],
|
187 |
+
"source": [
|
188 |
+
"# code to remove first few and last few frames of clips using moviepy\n",
|
189 |
+
"import os\n",
|
190 |
+
"from moviepy.editor import VideoFileClip\n",
|
191 |
+
"\n",
|
192 |
+
"def trim_clips(clips, start=0, end=0):\n",
|
193 |
+
" trimmed_clips = []\n",
|
194 |
+
" for clip in clips:\n",
|
195 |
+
" clip_path = os.path.join(\"clips\", clip)\n",
|
196 |
+
" video = VideoFileClip(clip_path)\n",
|
197 |
+
" trimmed = video.subclip(start, video.duration - end)\n",
|
198 |
+
" trimmed_clips.append(trimmed)\n",
|
199 |
+
" return trimmed_clips\n",
|
200 |
+
"\n",
|
201 |
+
"# Example usage\n",
|
202 |
+
"clips = os.listdir(\"clips\")\n",
|
203 |
+
"clips = [clip for clip in clips if clip.endswith(\".mp4\")]\n",
|
204 |
+
"\n",
|
205 |
+
"# Trim first 1 second and last 2 seconds\n",
|
206 |
+
"trimmed_clips = trim_clips(clips, 0.3, 0.3)\n"
|
207 |
+
]
|
208 |
+
}
|
209 |
+
],
|
210 |
+
"metadata": {
|
211 |
+
"kernelspec": {
|
212 |
+
"display_name": "venv",
|
213 |
+
"language": "python",
|
214 |
+
"name": "python3"
|
215 |
+
},
|
216 |
+
"language_info": {
|
217 |
+
"codemirror_mode": {
|
218 |
+
"name": "ipython",
|
219 |
+
"version": 3
|
220 |
+
},
|
221 |
+
"file_extension": ".py",
|
222 |
+
"mimetype": "text/x-python",
|
223 |
+
"name": "python",
|
224 |
+
"nbconvert_exporter": "python",
|
225 |
+
"pygments_lexer": "ipython3",
|
226 |
+
"version": "3.12.3"
|
227 |
+
}
|
228 |
+
},
|
229 |
+
"nbformat": 4,
|
230 |
+
"nbformat_minor": 2
|
231 |
+
}
|
output.mp4
ADDED
Binary file (168 kB). View file
|
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cv
|
2 |
+
moviepy
|
3 |
+
opencv-python
|
4 |
+
streamlit
|
trim_silence.py
ADDED
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import tempfile
|
3 |
+
import sys
|
4 |
+
import os
|
5 |
+
import logging
|
6 |
+
|
7 |
+
log_level = logging.ERROR
|
8 |
+
log_filename = 'silence_cutter.log'
|
9 |
+
logger = logging.getLogger('')
|
10 |
+
logger.setLevel(log_level)
|
11 |
+
log_handler = logging.FileHandler(log_filename, delay=True)
|
12 |
+
logger.addHandler(log_handler)
|
13 |
+
|
14 |
+
|
15 |
+
def findSilences(filename, dB = -25):
|
16 |
+
"""
|
17 |
+
returns a list:
|
18 |
+
even elements (0,2,4, ...) denote silence start time
|
19 |
+
uneven elements (1,3,5, ...) denote silence end time
|
20 |
+
|
21 |
+
"""
|
22 |
+
logging.debug(f"findSilences ()")
|
23 |
+
logging.debug(f" - filename = {filename}")
|
24 |
+
logging.debug(f" - dB = {dB}")
|
25 |
+
|
26 |
+
command = ["ffmpeg","-i",filename,
|
27 |
+
"-af","silencedetect=n=" + str (dB) + "dB:d=1",
|
28 |
+
"-f","null","-"]
|
29 |
+
output = subprocess.run (command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
30 |
+
s = str(output)
|
31 |
+
lines = s.split("\\n")
|
32 |
+
time_list = []
|
33 |
+
logging.debug(" lines: ```\n" + "\n".join(lines) + "```\n\n")
|
34 |
+
|
35 |
+
for line in lines:
|
36 |
+
if ("silencedetect" in line):
|
37 |
+
words = line.split(" ")
|
38 |
+
logging.debug(" words: " + str(words))
|
39 |
+
for i in range (len(words)):
|
40 |
+
if ("silence_start" in words[i]):
|
41 |
+
time_list.append (float(words[i+1]))
|
42 |
+
if "silence_end" in words[i]:
|
43 |
+
time_list.append (float (words[i+1]))
|
44 |
+
silence_section_list = list (zip(*[iter(time_list)]*2))
|
45 |
+
|
46 |
+
#return silence_section_list
|
47 |
+
return time_list
|
48 |
+
|
49 |
+
|
50 |
+
|
51 |
+
def getVideoDuration(filename:str) -> float:
|
52 |
+
logging.debug(f"getVideoDuration ()")
|
53 |
+
logging.debug(f" - filename = {filename}")
|
54 |
+
|
55 |
+
command = ["ffprobe","-i",filename,"-v","quiet",
|
56 |
+
"-show_entries","format=duration","-hide_banner",
|
57 |
+
"-of","default=noprint_wrappers=1:nokey=1"]
|
58 |
+
|
59 |
+
output = subprocess.run (command, stdout=subprocess.PIPE)
|
60 |
+
s = str(output.stdout, "UTF-8")
|
61 |
+
return float (s)
|
62 |
+
|
63 |
+
def getSectionsOfNewVideo (silences, duration):
|
64 |
+
"""Returns timings for parts, where the video should be kept"""
|
65 |
+
return [0.0] + silences + [duration]
|
66 |
+
|
67 |
+
|
68 |
+
def ffmpeg_filter_getSegmentFilter(videoSectionTimings):
|
69 |
+
ret = ""
|
70 |
+
for i in range (int (len(videoSectionTimings)/2)):
|
71 |
+
start = videoSectionTimings[2*i]
|
72 |
+
end = videoSectionTimings[2*i+1]
|
73 |
+
ret += "between(t," + str(start) + "," + str(end) + ")+"
|
74 |
+
# cut away last "+"
|
75 |
+
ret = ret[:-1]
|
76 |
+
return ret
|
77 |
+
|
78 |
+
def getFileContent_videoFilter(videoSectionTimings):
|
79 |
+
ret = "select='"
|
80 |
+
ret += ffmpeg_filter_getSegmentFilter (videoSectionTimings)
|
81 |
+
ret += "', setpts=N/FRAME_RATE/TB"
|
82 |
+
return ret
|
83 |
+
|
84 |
+
def getFileContent_audioFilter(videoSectionTimings):
|
85 |
+
ret = "aselect='"
|
86 |
+
ret += ffmpeg_filter_getSegmentFilter (videoSectionTimings)
|
87 |
+
ret += "', asetpts=N/SR/TB"
|
88 |
+
return ret
|
89 |
+
|
90 |
+
def writeFile (filename, content):
|
91 |
+
logging.debug(f"writeFile ()")
|
92 |
+
logging.debug(f" - filename = {filename}")
|
93 |
+
|
94 |
+
with open (filename, "w") as file:
|
95 |
+
file.write (str(content))
|
96 |
+
|
97 |
+
|
98 |
+
def ffmpeg_run (file, videoFilter, audioFilter, outfile):
|
99 |
+
logging.debug(f"ffmpeg_run ()")
|
100 |
+
|
101 |
+
# prepare filter files
|
102 |
+
vFile = tempfile.NamedTemporaryFile (mode="w", encoding="UTF-8", prefix="silence_video")
|
103 |
+
aFile = tempfile.NamedTemporaryFile (mode="w", encoding="UTF-8", prefix="silence_audio")
|
104 |
+
|
105 |
+
videoFilter_file = vFile.name #"/tmp/videoFilter" # TODO: replace with tempfile
|
106 |
+
audioFilter_file = aFile.name #"/tmp/audioFilter" # TODO: replace with tempfile
|
107 |
+
writeFile (videoFilter_file, videoFilter)
|
108 |
+
writeFile (audioFilter_file, audioFilter)
|
109 |
+
|
110 |
+
command = ["ffmpeg","-i",file,
|
111 |
+
"-filter_script:v",videoFilter_file,
|
112 |
+
"-filter_script:a",audioFilter_file,
|
113 |
+
outfile]
|
114 |
+
subprocess.run (command)
|
115 |
+
|
116 |
+
vFile.close()
|
117 |
+
aFile.close()
|
118 |
+
|
119 |
+
|
120 |
+
|
121 |
+
def cut_silences(infile, outfile, dB = -35):
|
122 |
+
logging.debug(f"cut_silences ()")
|
123 |
+
logging.debug(f" - infile = {infile}")
|
124 |
+
logging.debug(f" - outfile = {outfile}")
|
125 |
+
logging.debug(f" - dB = {dB}")
|
126 |
+
|
127 |
+
print ("detecting silences")
|
128 |
+
silences = findSilences (infile,dB)
|
129 |
+
duration = getVideoDuration (infile)
|
130 |
+
videoSegments = getSectionsOfNewVideo (silences, duration)
|
131 |
+
|
132 |
+
videoFilter = getFileContent_videoFilter (videoSegments)
|
133 |
+
audioFilter = getFileContent_audioFilter (videoSegments)
|
134 |
+
|
135 |
+
print ("create new video")
|
136 |
+
ffmpeg_run (infile, videoFilter, audioFilter, outfile)
|
137 |
+
|
138 |
+
def printHelp():
|
139 |
+
print ("Usage:")
|
140 |
+
print (" silence_cutter.py [infile] [optional: outfile] [optional: dB]")
|
141 |
+
print (" ")
|
142 |
+
print (" [outfile]")
|
143 |
+
print (" Default: [infile]_cut")
|
144 |
+
print (" ")
|
145 |
+
print (" [dB]")
|
146 |
+
print (" Default: -30")
|
147 |
+
print (" A suitable value might be around -50 to -35.")
|
148 |
+
print (" The lower the more volume will be defined das 'silent'")
|
149 |
+
print (" -30: Cut Mouse clicks and mouse movent; cuts are very recognizable.")
|
150 |
+
print (" -35: Cut inhaling breath before speaking; cuts are quite recognizable.")
|
151 |
+
print (" -40: Cuts are almost not recognizable.")
|
152 |
+
print (" -50: Cuts are almost not recognizable.")
|
153 |
+
print (" Cuts nothing, if there is background noise.")
|
154 |
+
print (" ")
|
155 |
+
print ("")
|
156 |
+
print ("Dependencies:")
|
157 |
+
print (" ffmpeg")
|
158 |
+
print (" ffprobe")
|
159 |
+
|
160 |
+
def main():
|
161 |
+
logging.debug(f"main ()")
|
162 |
+
args = sys.argv[1:]
|
163 |
+
if (len(args) < 1):
|
164 |
+
printHelp()
|
165 |
+
return
|
166 |
+
|
167 |
+
if (args[0] == "--help"):
|
168 |
+
printHelp()
|
169 |
+
return
|
170 |
+
|
171 |
+
infile = args[0]
|
172 |
+
|
173 |
+
if (not os.path.isfile (infile)):
|
174 |
+
print ("ERROR: The infile could not be found:\n" + infile)
|
175 |
+
return
|
176 |
+
|
177 |
+
# set default values for optionl arguments
|
178 |
+
tmp = os.path.splitext (infile)
|
179 |
+
outfile = tmp[0] + "_cut" + tmp[1]
|
180 |
+
dB = -20
|
181 |
+
|
182 |
+
if (len(args) >= 2):
|
183 |
+
outfile = args[1]
|
184 |
+
|
185 |
+
if (len(args) >= 3):
|
186 |
+
dB = args[2]
|
187 |
+
|
188 |
+
|
189 |
+
cut_silences (infile, outfile, dB)
|
190 |
+
|
191 |
+
|
192 |
+
if __name__ == "__main__":
|
193 |
+
# main()
|
194 |
+
|
195 |
+
import os
|
196 |
+
for file in os.listdir():
|
197 |
+
if file.endswith(".mp4"):
|
198 |
+
cut_silences(file, file.split(".mp4")[0] + "_cut.mp4", -20)
|
trimmed_clips/0_cut.mp4
ADDED
Binary file (164 kB). View file
|
|
trimmed_clips/100000_cut.mp4
ADDED
Binary file (193 kB). View file
|
|
trimmed_clips/1000_cut.mp4
ADDED
Binary file (126 kB). View file
|
|
trimmed_clips/100_cut.mp4
ADDED
Binary file (211 kB). View file
|
|
trimmed_clips/10_cut.mp4
ADDED
Binary file (155 kB). View file
|
|
trimmed_clips/11_cut.mp4
ADDED
Binary file (189 kB). View file
|
|
trimmed_clips/12_cut.mp4
ADDED
Binary file (161 kB). View file
|
|
trimmed_clips/13_cut.mp4
ADDED
Binary file (194 kB). View file
|
|
trimmed_clips/14_cut.mp4
ADDED
Binary file (193 kB). View file
|
|
trimmed_clips/15_cut.mp4
ADDED
Binary file (157 kB). View file
|
|
trimmed_clips/16_cut.mp4
ADDED
Binary file (172 kB). View file
|
|
trimmed_clips/17_cut.mp4
ADDED
Binary file (193 kB). View file
|
|
trimmed_clips/18_cut.mp4
ADDED
Binary file (251 kB). View file
|
|
trimmed_clips/19_cut.mp4
ADDED
Binary file (173 kB). View file
|
|
trimmed_clips/1_cut.mp4
ADDED
Binary file (142 kB). View file
|
|
trimmed_clips/20_cut.mp4
ADDED
Binary file (192 kB). View file
|
|
trimmed_clips/2_cut.mp4
ADDED
Binary file (132 kB). View file
|
|
trimmed_clips/30_cut.mp4
ADDED
Binary file (181 kB). View file
|
|
trimmed_clips/3_cut.mp4
ADDED
Binary file (162 kB). View file
|
|
trimmed_clips/40_cut.mp4
ADDED
Binary file (154 kB). View file
|
|
trimmed_clips/4_cut.mp4
ADDED
Binary file (165 kB). View file
|
|
trimmed_clips/50_cut.mp4
ADDED
Binary file (172 kB). View file
|
|
trimmed_clips/5_cut.mp4
ADDED
Binary file (167 kB). View file
|
|
trimmed_clips/60_cut.mp4
ADDED
Binary file (233 kB). View file
|
|
trimmed_clips/6_cut.mp4
ADDED
Binary file (165 kB). View file
|
|
trimmed_clips/70_cut.mp4
ADDED
Binary file (147 kB). View file
|
|
trimmed_clips/7_cut.mp4
ADDED
Binary file (171 kB). View file
|
|
trimmed_clips/80_cut.mp4
ADDED
Binary file (184 kB). View file
|
|
trimmed_clips/8_cut.mp4
ADDED
Binary file (169 kB). View file
|
|
trimmed_clips/90_cut.mp4
ADDED
Binary file (187 kB). View file
|
|
trimmed_clips/9_cut.mp4
ADDED
Binary file (166 kB). View file
|
|
trimmed_clips/Conclusion_cut.mp4
ADDED
Binary file (132 kB). View file
|
|
trimmed_clips/Intro_cut.mp4
ADDED
Binary file (319 kB). View file
|
|
utils.py
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from moviepy.editor import VideoFileClip, concatenate_videoclips
|
2 |
+
|
3 |
+
files = {
|
4 |
+
1: "1.mp4", 2: "2.mp4", 3: "3.mp4", 4: "4.mp4", 5: "5.mp4",
|
5 |
+
6: "6.mp4", 7: "7.mp4", 8: "8.mp4", 9: "9.mp4",
|
6 |
+
10: "10.mp4", 11: "11.mp4", 12: "12.mp4", 13: "13.mp4", 14: "14.mp4",
|
7 |
+
15: "15.mp4", 16: "16.mp4", 17: "17.mp4", 18: "18.mp4", 19: "19.mp4",
|
8 |
+
20: "20.mp4", 30: "30.mp4", 40: "40.mp4", 50: "50.mp4",
|
9 |
+
60: "60.mp4", 70: "70.mp4", 80: "80.mp4", 90: "90.mp4",
|
10 |
+
100: "100.mp4", 1000: "1000.mp4",
|
11 |
+
100000: "100000.mp4"
|
12 |
+
}
|
13 |
+
|
14 |
+
def number_to_clips(n):
|
15 |
+
components = []
|
16 |
+
if n >= 100000:
|
17 |
+
lakh = n // 100000
|
18 |
+
if lakh > 0:
|
19 |
+
components.append(lakh)
|
20 |
+
components.append(100000)
|
21 |
+
n %= 100000
|
22 |
+
if n >= 1000:
|
23 |
+
thousand = n // 1000
|
24 |
+
if thousand > 0:
|
25 |
+
components.append(thousand)
|
26 |
+
components.append(1000)
|
27 |
+
n %= 1000
|
28 |
+
if n >= 100:
|
29 |
+
hundred = n // 100
|
30 |
+
if hundred > 0:
|
31 |
+
components.append(hundred)
|
32 |
+
components.append(100)
|
33 |
+
n %= 100
|
34 |
+
if n > 20:
|
35 |
+
tens = (n // 10) * 10
|
36 |
+
if tens > 0:
|
37 |
+
components.append(tens)
|
38 |
+
n %= 10
|
39 |
+
if n > 0:
|
40 |
+
components.append(n)
|
41 |
+
return components
|
42 |
+
|
43 |
+
def generate_clip_sequence(n):
|
44 |
+
components = number_to_clips(n)
|
45 |
+
clip_sequence = []
|
46 |
+
for component in components:
|
47 |
+
if component in files:
|
48 |
+
clip_sequence.append(files[component])
|
49 |
+
else:
|
50 |
+
# Break down further if component is not in files
|
51 |
+
sub_components = number_to_clips(component)
|
52 |
+
clip_sequence.extend([files[sub] for sub in sub_components])
|
53 |
+
return clip_sequence
|
54 |
+
|
55 |
+
|
56 |
+
def trimmed_clip_path(clip):
|
57 |
+
return f"trimmed_clips/{clip.split('.mp4')[0]}_cut.mp4"
|
58 |
+
|
59 |
+
|
60 |
+
def get_clip_duration(clip):
|
61 |
+
try:
|
62 |
+
clip = VideoFileClip(trimmed_clip_path(clip))
|
63 |
+
return clip.duration
|
64 |
+
except Exception as e:
|
65 |
+
print(f"Error loading clip {trimmed_clip_path(clip)}: {e}")
|
66 |
+
return 0
|
67 |
+
|
68 |
+
|
69 |
+
|
70 |
+
def cut_clip(clip, st, en):
|
71 |
+
"""
|
72 |
+
Cuts the given clip from start time `st` to end time `en`.
|
73 |
+
"""
|
74 |
+
return clip.subclip(st, en)
|
75 |
+
|
76 |
+
|
77 |
+
|
78 |
+
def create_video(number,st, en, output_file="output.mp4"):
|
79 |
+
"""
|
80 |
+
Creates a video for the given number using pre-defined video clips.
|
81 |
+
"""
|
82 |
+
|
83 |
+
# Special files
|
84 |
+
intro_file = "trimmed_clips/Intro_cut.mp4"
|
85 |
+
conclusion_file = "trimmed_clips/Conclusion_cut.mp4"
|
86 |
+
|
87 |
+
clips_to_combine = [intro_file]
|
88 |
+
|
89 |
+
clips = generate_clip_sequence(number)
|
90 |
+
for clip in clips:
|
91 |
+
clips_to_combine.append(trimmed_clip_path(clip))
|
92 |
+
|
93 |
+
clips_to_combine.append(conclusion_file)
|
94 |
+
|
95 |
+
# Load and combine video clips
|
96 |
+
video_clips = []
|
97 |
+
for clip_path in clips_to_combine:
|
98 |
+
try:
|
99 |
+
clip = VideoFileClip(clip_path)
|
100 |
+
clip = cut_clip(clip, st, clip.duration - en)
|
101 |
+
video_clips.append(clip)
|
102 |
+
except Exception as e:
|
103 |
+
print(f"Error loading clip {clip_path}: {e}")
|
104 |
+
|
105 |
+
# Concatenate the video clips
|
106 |
+
if video_clips:
|
107 |
+
final_video = concatenate_videoclips(video_clips)
|
108 |
+
final_video.write_videofile(output_file, codec="libx264", audio_codec="aac")
|
109 |
+
else:
|
110 |
+
print("No clips to combine. Video creation failed.")
|
111 |
+
|
112 |
+
|
113 |
+
def create_advanced_video(number, trim_settings, output_file="output.mp4"):
|
114 |
+
intro_file = "trimmed_clips/Intro_cut.mp4"
|
115 |
+
conclusion_file = "trimmed_clips/Conclusion_cut.mp4"
|
116 |
+
|
117 |
+
clips_to_combine = [intro_file]
|
118 |
+
clips = generate_clip_sequence(number)
|
119 |
+
|
120 |
+
video_clips = []
|
121 |
+
for i, clip_path in enumerate(clips):
|
122 |
+
try:
|
123 |
+
clip = VideoFileClip(trimmed_clip_path(clip_path))
|
124 |
+
trim_start, trim_end = trim_settings[i]
|
125 |
+
trimmed_clip = cut_clip(clip, trim_start, clip.duration - trim_end)
|
126 |
+
video_clips.append(trimmed_clip)
|
127 |
+
except Exception as e:
|
128 |
+
print(f"Error loading clip {clip_path}: {e}")
|
129 |
+
|
130 |
+
clips_to_combine.extend(video_clips)
|
131 |
+
clips_to_combine.append(conclusion_file)
|
132 |
+
|
133 |
+
if video_clips:
|
134 |
+
final_video = concatenate_videoclips(video_clips)
|
135 |
+
final_video.write_videofile(output_file, codec="libx264", audio_codec="aac")
|
136 |
+
else:
|
137 |
+
print("No clips to combine. Video creation failed.")
|
138 |
+
|
139 |
+
# def main():
|
140 |
+
# """
|
141 |
+
# Main function to repeatedly prompt user input and generate videos.
|
142 |
+
# """
|
143 |
+
# while True:
|
144 |
+
# try:
|
145 |
+
# number = int(input("Enter a number between 1 and 9999999 (or 0 to exit): "))
|
146 |
+
# if number == 0:
|
147 |
+
# print("Exiting...")
|
148 |
+
# break
|
149 |
+
# elif number < 1 or number > 9999999:
|
150 |
+
# print("Invalid input. Please enter a number between 1 and 9999999.")
|
151 |
+
# continue
|
152 |
+
# create_video(number)
|
153 |
+
# except ValueError:
|
154 |
+
# print("Invalid input. Please enter a valid number.")
|
155 |
+
|
156 |
+
# if __name__ == "__main__":
|
157 |
+
# main()
|