Iskaj commited on
Commit
ccea5f9
1 Parent(s): 9b8a658

add Prajakta's changes to doc

Browse files
Files changed (3) hide show
  1. clip_data.ipynb +0 -423
  2. clip_data.py +92 -0
  3. videohash.py +78 -5
clip_data.ipynb DELETED
@@ -1,423 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "code",
5
- "execution_count": 5,
6
- "metadata": {},
7
- "outputs": [
8
- {
9
- "name": "stderr",
10
- "output_type": "stream",
11
- "text": [
12
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.ipify.org:443\n",
13
- "DEBUG:urllib3.connectionpool:https://api.ipify.org:443 \"GET / HTTP/1.1\" 200 15\n",
14
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.gradio.app:443\n",
15
- "DEBUG:urllib3.connectionpool:https://api.gradio.app:443 \"POST /gradio-initiated-analytics/ HTTP/1.1\" 200 31\n",
16
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.gradio.app:443\n",
17
- "DEBUG:urllib3.connectionpool:https://api.gradio.app:443 \"POST /gradio-initiated-analytics/ HTTP/1.1\" 200 31\n",
18
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.gradio.app:443\n",
19
- "DEBUG:urllib3.connectionpool:https://api.gradio.app:443 \"GET /pkg-version HTTP/1.1\" 200 20\n",
20
- "DEBUG:asyncio:Using selector: KqueueSelector\n",
21
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.ipify.org:443\n"
22
- ]
23
- },
24
- {
25
- "name": "stdout",
26
- "output_type": "stream",
27
- "text": [
28
- "Using cache from '/Users/ijanssen/videomatch/gradio_cached_examples/15' directory. If method or examples have changed since last caching, delete this folder to clear cache.\n"
29
- ]
30
- },
31
- {
32
- "name": "stderr",
33
- "output_type": "stream",
34
- "text": [
35
- "DEBUG:urllib3.connectionpool:https://api.ipify.org:443 \"GET / HTTP/1.1\" 200 15\n",
36
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.gradio.app:443\n",
37
- "DEBUG:urllib3.connectionpool:https://api.gradio.app:443 \"POST /gradio-initiated-analytics/ HTTP/1.1\" 200 31\n",
38
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.gradio.app:443\n",
39
- "DEBUG:urllib3.connectionpool:https://api.gradio.app:443 \"POST /gradio-initiated-analytics/ HTTP/1.1\" 200 31\n",
40
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.gradio.app:443\n",
41
- "DEBUG:urllib3.connectionpool:https://api.gradio.app:443 \"GET /pkg-version HTTP/1.1\" 200 20\n",
42
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.ipify.org:443\n",
43
- "DEBUG:urllib3.connectionpool:https://api.ipify.org:443 \"GET / HTTP/1.1\" 200 15\n",
44
- "DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.gradio.app:443\n",
45
- "DEBUG:urllib3.connectionpool:https://api.gradio.app:443 \"POST /gradio-initiated-analytics/ HTTP/1.1\" 200 31\n"
46
- ]
47
- },
48
- {
49
- "name": "stdout",
50
- "output_type": "stream",
51
- "text": [
52
- "Part Start = 5.0, Part Cutout = 5.0, Part Mid = 5.0, Part End = 135.03\n",
53
- "Moviepy - Building video videos/Ploumen_CO_5.0s_to_10.0_at_15.0.mp4.\n",
54
- "MoviePy - Writing audio in Ploumen_CO_5.0s_to_10.0_at_15.0TEMP_MPY_wvf_snd.mp4\n"
55
- ]
56
- },
57
- {
58
- "name": "stderr",
59
- "output_type": "stream",
60
- "text": [
61
- " \r"
62
- ]
63
- },
64
- {
65
- "name": "stdout",
66
- "output_type": "stream",
67
- "text": [
68
- "MoviePy - Done.\n",
69
- "Moviepy - Writing video videos/Ploumen_CO_5.0s_to_10.0_at_15.0.mp4\n",
70
- "\n"
71
- ]
72
- },
73
- {
74
- "name": "stderr",
75
- "output_type": "stream",
76
- "text": [
77
- " \r"
78
- ]
79
- },
80
- {
81
- "name": "stdout",
82
- "output_type": "stream",
83
- "text": [
84
- "Moviepy - Done !\n",
85
- "Moviepy - video ready videos/Ploumen_CO_5.0s_to_10.0_at_15.0.mp4\n"
86
- ]
87
- }
88
- ],
89
- "source": [
90
- "import moviepy\n",
91
- "from moviepy.editor import concatenate_videoclips\n",
92
- "from moviepy.video.io.VideoFileClip import VideoFileClip\n",
93
- "from moviepy.audio.io.AudioFileClip import AudioFileClip\n",
94
- "from moviepy.audio.AudioClip import CompositeAudioClip\n",
95
- "\n",
96
- "from app import change_ffmpeg_fps\n",
97
- "\n",
98
- "def add_logo(input_clip, output_clip_name, logo_file_name, logo_duration, position=(\"right\", \"top\")):\n",
99
- " logo = (moviepy.ImageClip(logo_file_name)\n",
100
- " .set_duration(logo_duration)\n",
101
- " .resize(height=50) # if you need to resize...\n",
102
- " .margin(right=8, top=8, opacity=0) # (optional) logo-border padding\n",
103
- " .set_pos(position))\n",
104
- "\n",
105
- " output_clip = moviepy.CompositeVideoClip([input_clip, logo])\n",
106
- " output_clip.write_videofile(output_clip_name)\n",
107
- " return output_clip\n",
108
- "\n",
109
- "def edit_remove_part(input_filename, start_s, end_s, FPS=5):\n",
110
- " \"\"\"Remove a segment of an .mp4 by and change its FPS. Keeps the audio intact by audio_codec='aac' parameter\"\"\"\n",
111
- " # input_video = change_ffmpeg_fps(VideoFileClip(input_filename), fps=FPS) # Load video and change fps for faster processing\n",
112
- " input_filename_no_ext, ext = input_filename.split('.')\n",
113
- " input_video = VideoFileClip(input_filename)\n",
114
- "\n",
115
- " # Remove part video and return result\n",
116
- " video = input_video.cutout(start_s, end_s)\n",
117
- "\n",
118
- " # Write Video\n",
119
- " output_filename = input_filename_no_ext + f\"_RM_{start_s}s_to_{end_s}.{ext}\"\n",
120
- " video.write_videofile(output_filename, audio_codec='aac')\n",
121
- "\n",
122
- "def edit_change_order(input_filename, start_s, end_s, insert_s, FPS=5):\n",
123
- " \"\"\"Take start_s to end_s out of the video and insert it at insert_s. Keeps the audio intact by audio_codec='aac' parameter\"\"\"\n",
124
- " # input_video = change_ffmpeg_fps(VideoFileClip(input_filename), fps=FPS) # Load video and change fps for faster processing\n",
125
- " input_filename_no_ext, ext = input_filename.split('.')\n",
126
- " input_video = VideoFileClip(input_filename)\n",
127
- " assert not (insert_s > start_s and insert_s < end_s), \"Insert time can't be in cutout time!\"\n",
128
- " assert (end_s > start_s), \"End_s should be higher than start_s!\"\n",
129
- "\n",
130
- " # Cut out a part and insert it somewhere else\n",
131
- " if insert_s < start_s and insert_s < end_s:\n",
132
- " part_start = input_video.subclip(0.0, insert_s)\n",
133
- " part_cutout = input_video.subclip(start_s, end_s)\n",
134
- " part_mid = input_video.subclip(insert_s, start_s)\n",
135
- " part_end = input_video.subclip(end_s, input_video.duration)\n",
136
- " video = concatenate_videoclips([part_start, part_cutout, part_mid, part_end])\n",
137
- " elif insert_s > start_s and insert_s > end_s:\n",
138
- " part_start = input_video.subclip(0.0, start_s)\n",
139
- " part_cutout = input_video.subclip(start_s, end_s)\n",
140
- " part_mid = input_video.subclip(end_s, insert_s)\n",
141
- " part_end = input_video.subclip(insert_s, input_video.duration)\n",
142
- " print(f\"Part Start = {part_start.duration}, Part Cutout = {part_cutout.duration}, Part Mid = {part_mid.duration}, Part End = {part_end.duration}\")\n",
143
- " video = concatenate_videoclips([part_start, part_mid, part_cutout, part_end])\n",
144
- "\n",
145
- " # Write Video\n",
146
- " output_filename = input_filename_no_ext + f\"_CO_{start_s}s_to_{end_s}_at_{insert_s}.{ext}\"\n",
147
- " video.write_videofile(output_filename, audio_codec='aac')\n",
148
- "\n",
149
- "# edit_remove_part(\"videos/Ploumen.mp4\", start_s = 5.0, end_s = 10.0)\n",
150
- "# edit_change_order(\"videos/Ploumen.mp4\", start_s = 5.0, end_s = 10.0, insert_s = 15.0)\n",
151
- "\n",
152
- "\n"
153
- ]
154
- },
155
- {
156
- "cell_type": "code",
157
- "execution_count": 21,
158
- "metadata": {},
159
- "outputs": [
160
- {
161
- "name": "stdout",
162
- "output_type": "stream",
163
- "text": [
164
- "[(51, 92), (14, 98), (64, 85), (63, 90), (63, 96)]\n",
165
- "[112, 0, 53, 96, 123]\n"
166
- ]
167
- }
168
- ],
169
- "source": [
170
- "\n",
171
- "import numpy as np\n",
172
- "\n",
173
- "MAX = 130\n",
174
- "\n",
175
- "# Get some random start_s and end_s pairs where start_s is always lower than end_s\n",
176
- "rand_start_s = np.random.randint(low=0, high=MAX, size=5)\n",
177
- "rand_end_s = np.random.randint(low=0, high=MAX, size=5)\n",
178
- "rand_pairs = zip(rand_start_s, rand_end_s)\n",
179
- "rand_pairs = [(x,y) if (x < y) else (y, x) for x, y in rand_pairs]\n",
180
- "\n",
181
- "def get_insert_s(start_s, end_s, max=MAX):\n",
182
- " \"\"\" Get a insert_s that is outside the start_s and end_s \"\"\"\n",
183
- " random_choice = bool(np.random.randint(low=0, high=2, size=1)[0])\n",
184
- " if random_choice:\n",
185
- " return np.random.randint(low=0, high=start_s, size=1)[0]\n",
186
- " else:\n",
187
- " return np.random.randint(low=end_s, high=MAX, size=1)[0]\n",
188
- "\n",
189
- "rand_insert_s = [get_insert_s(x, y) for x, y in rand_pairs]\n",
190
- "\n",
191
- "print(rand_pairs)\n",
192
- "print(rand_insert_s)\n",
193
- "\n"
194
- ]
195
- },
196
- {
197
- "cell_type": "code",
198
- "execution_count": 22,
199
- "metadata": {},
200
- "outputs": [
201
- {
202
- "name": "stdout",
203
- "output_type": "stream",
204
- "text": [
205
- "Part Start = 51.0, Part Cutout = 41, Part Mid = 20, Part End = 38.03\n",
206
- "Moviepy - Building video videos/Ploumen_CO_51s_to_92_at_112.mp4.\n",
207
- "MoviePy - Writing audio in Ploumen_CO_51s_to_92_at_112TEMP_MPY_wvf_snd.mp4\n"
208
- ]
209
- },
210
- {
211
- "name": "stderr",
212
- "output_type": "stream",
213
- "text": [
214
- " \r"
215
- ]
216
- },
217
- {
218
- "name": "stdout",
219
- "output_type": "stream",
220
- "text": [
221
- "MoviePy - Done.\n",
222
- "Moviepy - Writing video videos/Ploumen_CO_51s_to_92_at_112.mp4\n",
223
- "\n"
224
- ]
225
- },
226
- {
227
- "name": "stderr",
228
- "output_type": "stream",
229
- "text": [
230
- " \r"
231
- ]
232
- },
233
- {
234
- "name": "stdout",
235
- "output_type": "stream",
236
- "text": [
237
- "Moviepy - Done !\n",
238
- "Moviepy - video ready videos/Ploumen_CO_51s_to_92_at_112.mp4\n",
239
- "Moviepy - Building video videos/Ploumen_CO_14s_to_98_at_0.mp4.\n",
240
- "MoviePy - Writing audio in Ploumen_CO_14s_to_98_at_0TEMP_MPY_wvf_snd.mp4\n"
241
- ]
242
- },
243
- {
244
- "name": "stderr",
245
- "output_type": "stream",
246
- "text": [
247
- " \r"
248
- ]
249
- },
250
- {
251
- "name": "stdout",
252
- "output_type": "stream",
253
- "text": [
254
- "MoviePy - Done.\n",
255
- "Moviepy - Writing video videos/Ploumen_CO_14s_to_98_at_0.mp4\n",
256
- "\n"
257
- ]
258
- },
259
- {
260
- "name": "stderr",
261
- "output_type": "stream",
262
- "text": [
263
- " \r"
264
- ]
265
- },
266
- {
267
- "name": "stdout",
268
- "output_type": "stream",
269
- "text": [
270
- "Moviepy - Done !\n",
271
- "Moviepy - video ready videos/Ploumen_CO_14s_to_98_at_0.mp4\n",
272
- "Moviepy - Building video videos/Ploumen_CO_64s_to_85_at_53.mp4.\n",
273
- "MoviePy - Writing audio in Ploumen_CO_64s_to_85_at_53TEMP_MPY_wvf_snd.mp4\n"
274
- ]
275
- },
276
- {
277
- "name": "stderr",
278
- "output_type": "stream",
279
- "text": [
280
- " \r"
281
- ]
282
- },
283
- {
284
- "name": "stdout",
285
- "output_type": "stream",
286
- "text": [
287
- "MoviePy - Done.\n",
288
- "Moviepy - Writing video videos/Ploumen_CO_64s_to_85_at_53.mp4\n",
289
- "\n"
290
- ]
291
- },
292
- {
293
- "name": "stderr",
294
- "output_type": "stream",
295
- "text": [
296
- " \r"
297
- ]
298
- },
299
- {
300
- "name": "stdout",
301
- "output_type": "stream",
302
- "text": [
303
- "Moviepy - Done !\n",
304
- "Moviepy - video ready videos/Ploumen_CO_64s_to_85_at_53.mp4\n",
305
- "Part Start = 63.0, Part Cutout = 27, Part Mid = 6, Part End = 54.03\n",
306
- "Moviepy - Building video videos/Ploumen_CO_63s_to_90_at_96.mp4.\n",
307
- "MoviePy - Writing audio in Ploumen_CO_63s_to_90_at_96TEMP_MPY_wvf_snd.mp4\n"
308
- ]
309
- },
310
- {
311
- "name": "stderr",
312
- "output_type": "stream",
313
- "text": [
314
- " \r"
315
- ]
316
- },
317
- {
318
- "name": "stdout",
319
- "output_type": "stream",
320
- "text": [
321
- "MoviePy - Done.\n",
322
- "Moviepy - Writing video videos/Ploumen_CO_63s_to_90_at_96.mp4\n",
323
- "\n"
324
- ]
325
- },
326
- {
327
- "name": "stderr",
328
- "output_type": "stream",
329
- "text": [
330
- " \r"
331
- ]
332
- },
333
- {
334
- "name": "stdout",
335
- "output_type": "stream",
336
- "text": [
337
- "Moviepy - Done !\n",
338
- "Moviepy - video ready videos/Ploumen_CO_63s_to_90_at_96.mp4\n",
339
- "Part Start = 63.0, Part Cutout = 33, Part Mid = 27, Part End = 27.03\n",
340
- "Moviepy - Building video videos/Ploumen_CO_63s_to_96_at_123.mp4.\n",
341
- "MoviePy - Writing audio in Ploumen_CO_63s_to_96_at_123TEMP_MPY_wvf_snd.mp4\n"
342
- ]
343
- },
344
- {
345
- "name": "stderr",
346
- "output_type": "stream",
347
- "text": [
348
- " \r"
349
- ]
350
- },
351
- {
352
- "name": "stdout",
353
- "output_type": "stream",
354
- "text": [
355
- "MoviePy - Done.\n",
356
- "Moviepy - Writing video videos/Ploumen_CO_63s_to_96_at_123.mp4\n",
357
- "\n"
358
- ]
359
- },
360
- {
361
- "name": "stderr",
362
- "output_type": "stream",
363
- "text": [
364
- " \r"
365
- ]
366
- },
367
- {
368
- "name": "stdout",
369
- "output_type": "stream",
370
- "text": [
371
- "Moviepy - Done !\n",
372
- "Moviepy - video ready videos/Ploumen_CO_63s_to_96_at_123.mp4\n"
373
- ]
374
- }
375
- ],
376
- "source": [
377
- "for pair, insert_s in zip(rand_pairs, rand_insert_s):\n",
378
- " edit_change_order(\"videos/Ploumen.mp4\", start_s = pair[0], end_s = pair[1], insert_s = insert_s)"
379
- ]
380
- },
381
- {
382
- "cell_type": "code",
383
- "execution_count": null,
384
- "metadata": {},
385
- "outputs": [],
386
- "source": []
387
- },
388
- {
389
- "cell_type": "code",
390
- "execution_count": null,
391
- "metadata": {},
392
- "outputs": [],
393
- "source": []
394
- }
395
- ],
396
- "metadata": {
397
- "kernelspec": {
398
- "display_name": "Python 3.9.13 64-bit",
399
- "language": "python",
400
- "name": "python3"
401
- },
402
- "language_info": {
403
- "codemirror_mode": {
404
- "name": "ipython",
405
- "version": 3
406
- },
407
- "file_extension": ".py",
408
- "mimetype": "text/x-python",
409
- "name": "python",
410
- "nbconvert_exporter": "python",
411
- "pygments_lexer": "ipython3",
412
- "version": "3.9.13"
413
- },
414
- "orig_nbformat": 4,
415
- "vscode": {
416
- "interpreter": {
417
- "hash": "397704579725e15f5c7cb49fe5f0341eb7531c82d19f2c29d197e8b64ab5776b"
418
- }
419
- }
420
- },
421
- "nbformat": 4,
422
- "nbformat_minor": 2
423
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
clip_data.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import moviepy
2
+ from moviepy.editor import concatenate_videoclips
3
+ from moviepy.video.io.VideoFileClip import VideoFileClip
4
+
5
+
6
+ def add_logo(input_clip, output_clip_name, logo_file_name, logo_duration, position=("right", "top")):
7
+ """Add logo to the videos to replicate edited videos with logos.
8
+
9
+ Args:
10
+ input_clip (VideoFileClip): The video to be edited.
11
+ output_clip_name (str): The file name of where the edited video is to be saved.
12
+ logo_file_name (str): The name of the logo image to be added.
13
+ logo_duration (float): The duration in seconds (from the beginning) where the logo will appear on the video.
14
+
15
+ Returns:
16
+ None.
17
+ """
18
+
19
+ logo = (moviepy.ImageClip(logo_file_name)
20
+ .set_duration(logo_duration)
21
+ .resize(height=50) # if you need to resize...
22
+ .margin(right=8, top=8, opacity=0) # (optional) logo-border padding
23
+ .set_pos(position))
24
+
25
+ output_clip = moviepy.CompositeVideoClip([input_clip, logo])
26
+ output_clip.write_videofile(output_clip_name)
27
+
28
+ def edit_remove_part(input_filename, start_s, end_s):
29
+ """Remove a segment of an .mp4 by and change its FPS. Keeps the audio intact by audio_codec='aac' parameter.
30
+
31
+ Args:
32
+ input_filename (str): The name of the input video to be edited.
33
+ start_s (float): The start time in seconds of the segment to be removed.
34
+ end_s (float): The end time in seconds of the segment to be removed.
35
+
36
+ Returns:
37
+ None.
38
+ """
39
+
40
+ input_filename_no_ext, ext = input_filename.split('.')
41
+ input_video = VideoFileClip(input_filename)
42
+
43
+ # Remove part video and return result
44
+ video = input_video.cutout(start_s, end_s)
45
+
46
+ # Write Video
47
+ output_filename = input_filename_no_ext + f"_RM_{start_s}s_to_{end_s}.{ext}"
48
+ video.write_videofile(output_filename, audio_codec='aac')
49
+
50
+ def edit_change_order(input_filename, start_s, end_s, insert_s):
51
+ """Take start_s to end_s out of the video and insert it at insert_s. Keeps the audio intact by audio_codec='aac' parameter.
52
+
53
+ Args:
54
+ input_filename (str): The name of the input video to be edited.
55
+ start_s (float): The start time in seconds of the segment to be removed.
56
+ end_s (float): The end time in seconds of the segment to be removed.
57
+ insert_s (float): The time in seconds where the removed segment is to be re-added.
58
+
59
+ Returns:
60
+ None.
61
+ """
62
+
63
+ # Load in video
64
+ input_filename_no_ext, ext = input_filename.split('.')
65
+ input_video = VideoFileClip(input_filename)
66
+
67
+ # Assert that the insert timestamp is not originally a part of the segment to be removed
68
+ # And that end_s is greater than start_s
69
+ assert not (insert_s > start_s and insert_s < end_s), "Insert time can't be in cutout time!"
70
+ assert (end_s > start_s), "End_s should be higher than start_s!"
71
+
72
+ # Cut out a part and insert it somewhere else
73
+ if insert_s < start_s and insert_s < end_s:
74
+
75
+ part_start = input_video.subclip(0.0, insert_s)
76
+ part_cutout = input_video.subclip(start_s, end_s)
77
+ part_mid = input_video.subclip(insert_s, start_s)
78
+ part_end = input_video.subclip(end_s, input_video.duration)
79
+ video = concatenate_videoclips([part_start, part_cutout, part_mid, part_end])
80
+
81
+ elif insert_s > start_s and insert_s > end_s:
82
+
83
+ part_start = input_video.subclip(0.0, start_s)
84
+ part_cutout = input_video.subclip(start_s, end_s)
85
+ part_mid = input_video.subclip(end_s, insert_s)
86
+ part_end = input_video.subclip(insert_s, input_video.duration)
87
+ print(f"Part Start = {part_start.duration}, Part Cutout = {part_cutout.duration}, Part Mid = {part_mid.duration}, Part End = {part_end.duration}")
88
+ video = concatenate_videoclips([part_start, part_mid, part_cutout, part_end])
89
+
90
+ # Write video location
91
+ output_filename = input_filename_no_ext + f"_CO_{start_s}s_to_{end_s}_at_{insert_s}.{ext}"
92
+ video.write_videofile(output_filename, audio_codec='aac')
videohash.py CHANGED
@@ -11,17 +11,34 @@ from moviepy.editor import VideoFileClip
11
  from moviepy.video.fx.all import crop
12
  import numpy as np
13
  from pytube import YouTube
 
14
 
15
  from config import FPS, VIDEO_DIRECTORY
16
 
17
 
18
  def filepath_from_url(url):
19
- """Return filepath based on a md5 hash of a url."""
 
 
 
 
 
 
 
20
  return os.path.join(VIDEO_DIRECTORY, hashlib.md5(url.encode()).hexdigest())
21
 
22
  def download_video_from_url(url):
23
- """Download video from url or return md5 hash as video name"""
 
 
 
 
 
 
 
24
  start = time.time()
 
 
25
  filepath = filepath_from_url(url)
26
 
27
  # Check if it exists already
@@ -46,11 +63,19 @@ def download_video_from_url(url):
46
  return filepath
47
 
48
  def change_ffmpeg_fps(clip, fps=FPS):
49
- """ DOCSTRING HERE """
 
 
 
 
 
 
 
 
50
  # Hacking the ffmpeg call based on
51
  # https://github.com/Zulko/moviepy/blob/master/moviepy/video/io/ffmpeg_reader.py#L126
52
- import subprocess as sp
53
-
54
  cmd = [arg + ",fps=%d" % fps if arg.startswith("scale=") else arg for arg in clip.reader.proc.args]
55
  clip.reader.close()
56
  clip.reader.proc = sp.Popen(cmd, bufsize=clip.reader.bufsize,
@@ -60,21 +85,69 @@ def change_ffmpeg_fps(clip, fps=FPS):
60
  return clip
61
 
62
  def crop_video(clip, crop_percentage=0.75, w=224, h=224):
 
 
 
 
 
 
 
 
 
 
 
63
  # Original width and height- which combined with crop_percentage determines the size of the new video
64
  ow, oh = clip.size
65
 
66
  logging.info(f"Cropping and resizing video to ({w}, {h})")
 
 
 
67
  return crop(clip, x_center=ow/2, y_center=oh/2, width=int(ow*crop_percentage), height=int(crop_percentage*oh)).resize((w,h))
68
 
69
  def compute_hash(frame, hash_size=16):
 
 
 
 
 
 
 
 
 
70
  image = Image.fromarray(np.array(frame))
 
71
  return imagehash.phash(image, hash_size)
72
 
73
  def binary_array_to_uint8s(arr):
 
 
 
 
 
 
 
 
 
 
74
  bit_string = ''.join(str(1 * x) for l in arr for x in l)
 
 
75
  return [int(bit_string[i:i+8], 2) for i in range(0, len(bit_string), 8)]
76
 
77
  def compute_hashes(url: str, fps=FPS):
 
 
 
 
 
 
 
 
 
 
 
 
78
  try:
79
  filepath = download_video_from_url(url)
80
  clip = crop_video(VideoFileClip(filepath))
 
11
  from moviepy.video.fx.all import crop
12
  import numpy as np
13
  from pytube import YouTube
14
+ import subprocess as sp
15
 
16
  from config import FPS, VIDEO_DIRECTORY
17
 
18
 
19
  def filepath_from_url(url):
20
+ """Function to generate filepath from url.
21
+
22
+ Args:
23
+ url (str): The url of the input video.
24
+
25
+ Returns:
26
+ (str): Filepath of the video based on md5 hash of the url.
27
+ """
28
  return os.path.join(VIDEO_DIRECTORY, hashlib.md5(url.encode()).hexdigest())
29
 
30
  def download_video_from_url(url):
31
+ """Download video from url or return md5 hash as video name.
32
+
33
+ Args:
34
+ url (str): The url of the input video
35
+
36
+ Returns:
37
+ filepath (str): Filepath to the downloaded video from the url.
38
+ """
39
  start = time.time()
40
+
41
+ # Generate filepath from url
42
  filepath = filepath_from_url(url)
43
 
44
  # Check if it exists already
 
63
  return filepath
64
 
65
  def change_ffmpeg_fps(clip, fps=FPS):
66
+ """Change frame rate of a clip.
67
+
68
+ Args:
69
+ clip (moviepy.editor.VideoFileClip): Input clip.
70
+ fps (int): The desired frame rate for the clip.
71
+
72
+ Returns:
73
+ clip (moviepy.editor.VideoFileClip): New clip with the desired.
74
+ """
75
  # Hacking the ffmpeg call based on
76
  # https://github.com/Zulko/moviepy/blob/master/moviepy/video/io/ffmpeg_reader.py#L126
77
+
78
+ # Define ffmpeg style command
79
  cmd = [arg + ",fps=%d" % fps if arg.startswith("scale=") else arg for arg in clip.reader.proc.args]
80
  clip.reader.close()
81
  clip.reader.proc = sp.Popen(cmd, bufsize=clip.reader.bufsize,
 
85
  return clip
86
 
87
  def crop_video(clip, crop_percentage=0.75, w=224, h=224):
88
+ """Crop video clip to given crop percentage.
89
+
90
+ Args:
91
+ clip (moviepy.editor.VideoFileClip): Clip to be cropped.
92
+ crop_percentage (float): How much of the width and heights needs to remain after cropping.
93
+ width (float): Final width the video clip will be resized to.
94
+ height (float): Final height the video clip will be resized to.
95
+
96
+ Returns:
97
+ (moviepy.editor.VideoFileClip): Cropped and resized clip.
98
+ """
99
  # Original width and height- which combined with crop_percentage determines the size of the new video
100
  ow, oh = clip.size
101
 
102
  logging.info(f"Cropping and resizing video to ({w}, {h})")
103
+
104
+ # 75% of the width and height from the center of the clip is taken, so 25% is discarded
105
+ # The video is then resized to given w,h - for faster computation of hashes
106
  return crop(clip, x_center=ow/2, y_center=oh/2, width=int(ow*crop_percentage), height=int(crop_percentage*oh)).resize((w,h))
107
 
108
  def compute_hash(frame, hash_size=16):
109
+ """Compute (p)hashes of the given frame.
110
+
111
+ Args:
112
+ frame (numpy.ndarray): Frame from the video.
113
+ hash_size (int): Size of the required hash.
114
+
115
+ Returns:
116
+ (ndarray): Perceptual hash of the frame of size (hash_size, hash_size)
117
+ """
118
  image = Image.fromarray(np.array(frame))
119
+
120
  return imagehash.phash(image, hash_size)
121
 
122
  def binary_array_to_uint8s(arr):
123
+ """Convert binary array to form uint8s.
124
+
125
+ Args:
126
+ arr (numpy.ndarray): Frame from the video.
127
+
128
+ Returns:
129
+ (list): Hash converted from uint8 format
130
+ """
131
+
132
+ # First make a bitstring out of the (hash_size, hash_size) ndarray
133
  bit_string = ''.join(str(1 * x) for l in arr for x in l)
134
+
135
+ # Converting to uint8- segment at every 8th bit and convert to decimal value
136
  return [int(bit_string[i:i+8], 2) for i in range(0, len(bit_string), 8)]
137
 
138
  def compute_hashes(url: str, fps=FPS):
139
+ """Compute hashes of the video at the given url.
140
+
141
+ Args:
142
+ url (str): Url of the input video.
143
+
144
+ Yeilds:
145
+ ({str: int, str: ndarray}): Dict with the frame number and the corresponding hash.
146
+ """
147
+
148
+ # Try downloading the video from url. If that fails, load it directly from the url instead
149
+ # Then crop the video
150
+
151
  try:
152
  filepath = download_video_from_url(url)
153
  clip = crop_video(VideoFileClip(filepath))