Skip to content

Commit 7a1e8c4

Browse files
Day 15 - Video to Thumbnails to GIF with Moviepy
1 parent b63b66f commit 7a1e8c4

File tree

143 files changed

+1770
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+1770
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from conf import SAMPLE_INPUTS, SAMPLE_OUTPUTS
2+
from moviepy.editor import *
3+
from PIL import Image
4+
5+
source_path = os.path.join(SAMPLE_INPUTS, 'sample.mp4')
6+
thumbnail_dir = os.path.join(SAMPLE_OUTPUTS, "thumbnails")
7+
thumbnail_per_frame_dir = os.path.join(SAMPLE_OUTPUTS, "thumbnails-per-frame")
8+
thumbnail_per_half_second_dir = os.path.join(SAMPLE_OUTPUTS, "thumbnails-per-half-second")
9+
10+
os.makedirs(thumbnail_dir, exist_ok=True)
11+
os.makedirs(thumbnail_per_frame_dir, exist_ok=True)
12+
os.makedirs(thumbnail_per_half_second_dir, exist_ok=True)
13+
14+
15+
clip = VideoFileClip(source_path)
16+
print(clip.reader.fps) # frames per second
17+
print(clip.reader.nframes)
18+
print(clip.duration) # seconds
19+
duration = clip.duration # clip.reader.duration
20+
max_duration = int(duration) + 1
21+
for i in range(0, max_duration):
22+
frame = clip.get_frame(i)
23+
# print(frame) # np.array numpy array # inference
24+
new_img_filepath = os.path.join(thumbnail_dir, f"{i}.jpg")
25+
# print(f"frame at {i} seconds saved at {new_img_filepath}")
26+
new_img = Image.fromarray(frame)
27+
new_img.save(new_img_filepath)
28+
29+
30+
31+
print(clip.reader.fps) # frames per second
32+
print(clip.reader.nframes)
33+
34+
fps = clip.reader.fps
35+
nframes = clip.reader.nframes
36+
seconds = nframes / (fps * 1.0)
37+
38+
for i, frame in enumerate(clip.iter_frames()):
39+
# print(frame) # np.array numpy array # inference
40+
if i % fps == 0:
41+
current_ms = int((i / fps) * 1000)
42+
new_img_filepath = os.path.join(thumbnail_per_frame_dir, f"{current_ms}.jpg")
43+
# print(f"frame at {i} seconds saved at {new_img_filepath}")
44+
new_img = Image.fromarray(frame)
45+
new_img.save(new_img_filepath)
46+
47+
48+
49+
for i, frame in enumerate(clip.iter_frames()):
50+
# print(frame) # np.array numpy array # inference
51+
fphs = int(fps/2.0)
52+
if i % fphs == 0:
53+
current_ms = int((i / fps) * 1000)
54+
new_img_filepath = os.path.join(thumbnail_per_half_second_dir, f"{current_ms}.jpg")
55+
# print(f"frame at {i} seconds saved at {new_img_filepath}")
56+
new_img = Image.fromarray(frame)
57+
new_img.save(new_img_filepath)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from conf import SAMPLE_INPUTS, SAMPLE_OUTPUTS
2+
from moviepy.editor import * # ImageClip
3+
from PIL import Image
4+
5+
thumbnail_dir = os.path.join(SAMPLE_OUTPUTS, "thumbnails")
6+
thumbnail_per_frame_dir = os.path.join(SAMPLE_OUTPUTS, "thumbnails-per-frame")
7+
thumbnail_per_half_second_dir = os.path.join(SAMPLE_OUTPUTS, "thumbnails-per-half-second")
8+
output_video = os.path.join(SAMPLE_OUTPUTS, 'thumbs.mp4')
9+
10+
11+
this_dir = os.listdir(thumbnail_dir)
12+
filepaths = [os.path.join(thumbnail_dir, fname) for fname in this_dir if fname.endswith("jpg")]
13+
14+
# filepaths = []
15+
# for fname in this_dir:
16+
# if fname.endswith("jpg"):
17+
# path = os.path.join(thumbnail_dir, fname)
18+
# filepaths.append(path)
19+
20+
# print(filepaths)
21+
# clip = ImageSequenceClip(filepaths, fps=1)
22+
# clip.write_videofile(output_video)
23+
24+
25+
directory = {}
26+
27+
for root, dirs, files in os.walk(thumbnail_per_frame_dir):
28+
for fname in files:
29+
filepath = os.path.join(root, fname)
30+
try:
31+
key = float(fname.replace(".jpg", ""))
32+
except:
33+
key = None
34+
if key != None:
35+
directory[key] = filepath
36+
37+
new_paths = []
38+
for k in sorted(directory.keys()):
39+
filepath = directory[k]
40+
new_paths.append(filepath)
41+
42+
# clip = ImageSequenceClip(new_paths, fps=10)
43+
# clip.write_videofile(output_video)
44+
45+
my_clips = []
46+
for path in list(new_paths):
47+
frame = ImageClip(path)
48+
# print(frame.img) # numpy array
49+
my_clips.append(frame.img)
50+
51+
52+
clip = ImageSequenceClip(my_clips, fps=22)
53+
clip.write_videofile(output_video)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from conf import SAMPLE_INPUTS, SAMPLE_OUTPUTS
2+
from moviepy.editor import * # ImageClip
3+
from PIL import Image
4+
from moviepy.video.fx.all import crop
5+
6+
7+
source_path = os.path.join(SAMPLE_INPUTS, 'sample.mp4')
8+
9+
GIF_DIR = os.path.join(SAMPLE_OUTPUTS, "gifs")
10+
os.makedirs(GIF_DIR, exist_ok=True)
11+
12+
output_path1 = os.path.join(GIF_DIR, 'sample1.gif')
13+
output_path2 = os.path.join(GIF_DIR, 'sample2.gif')
14+
15+
clip = VideoFileClip(source_path)
16+
fps = clip.reader.fps
17+
subclip = clip.subclip(10, 20)
18+
subclip = subclip.resize(width=500)
19+
# subclip.write_gif(output_path1, fps=fps, program='ffmpeg')
20+
21+
22+
w, h = clip.size
23+
subclip2 = clip.subclip(10, 20)
24+
square_cropped_clip = crop(subclip2, width=320, height=320, x_center=w/2, y_center=h/2)
25+
26+
# square_cropped_clip.write_gif(output_path2, fps=fps, program='ffmpeg')
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from conf import SAMPLE_INPUTS, SAMPLE_OUTPUTS
2+
from moviepy.editor import *
3+
from moviepy.audio.fx.all import volumex
4+
from PIL import Image
5+
6+
source_path = os.path.join(SAMPLE_INPUTS, 'sample.mp4')
7+
source_audio_path = os.path.join(SAMPLE_INPUTS, 'audio.mp3')
8+
9+
mix_audio_dir = os.path.join(SAMPLE_OUTPUTS, "mixed-audio")
10+
os.makedirs(mix_audio_dir, exist_ok=True)
11+
og_audio_path = os.path.join(mix_audio_dir, 'og.mp3')
12+
final_audio_path = os.path.join(mix_audio_dir, 'final-audio.mp3')
13+
final_video_path = os.path.join(mix_audio_dir, 'final-video.mp4')
14+
15+
video_clip = VideoFileClip(source_path)
16+
17+
original_audio = video_clip.audio
18+
original_audio.write_audiofile(og_audio_path)
19+
20+
background_audio_clip = AudioFileClip(source_audio_path)
21+
bg_music = background_audio_clip.subclip(0, video_clip.duration)
22+
23+
24+
# bg_music = bg_music.fx(volumex, 0.10)
25+
bg_music = bg_music.volumex(0.10)
26+
# bg_music.write_audiofile()
27+
28+
final_audio = CompositeAudioClip([original_audio, bg_music])
29+
final_audio.write_audiofile(final_audio_path, fps=original_audio.fps)
30+
31+
32+
# new_audio = AudioFileClip(final_audio_path)
33+
# final_clip = video_clip.set_audio(new_audio)
34+
35+
final_clip = video_clip.set_audio(final_audio)
36+
final_clip.write_videofile(final_video_path, codec='libx264', audio_codec="aac")
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from conf import SAMPLE_INPUTS, SAMPLE_OUTPUTS
2+
from moviepy.editor import *
3+
from moviepy.audio.fx.all import volumex
4+
from PIL import Image
5+
6+
source_path = os.path.join(SAMPLE_INPUTS, 'sample.mp4')
7+
source_audio_path = os.path.join(SAMPLE_INPUTS, 'audio.mp3')
8+
9+
mix_audio_dir = os.path.join(SAMPLE_OUTPUTS, "mixed-audio")
10+
os.makedirs(mix_audio_dir, exist_ok=True)
11+
og_audio_path = os.path.join(mix_audio_dir, 'og.mp3')
12+
final_audio_path = os.path.join(mix_audio_dir, 'overlay-audio.mp3')
13+
final_video_path = os.path.join(mix_audio_dir, 'overlay-video.mp4')
14+
15+
video_clip = VideoFileClip(source_path)
16+
17+
original_audio = video_clip.audio
18+
original_audio.write_audiofile(og_audio_path)
19+
20+
background_audio_clip = AudioFileClip(source_audio_path)
21+
#
22+
w, h = video_clip.size
23+
fps = video_clip.fps
24+
25+
intro_duration = 5
26+
intro_text = TextClip("Hello world!", fontsize=70, color='white', size=video_clip.size)
27+
intro_text = intro_text.set_duration(intro_duration)
28+
intro_text = intro_text.set_fps(fps)
29+
intro_text = intro_text.set_pos("center")
30+
31+
intro_music = background_audio_clip.subclip(0, intro_duration)
32+
33+
intro_text = intro_text.set_audio(intro_music)
34+
35+
# intro_text.write_videofile(final_video_path)
36+
watermark_size = 60
37+
watermark_text = TextClip("CFE", fontsize=watermark_size, color='white', align='West', size=(w, watermark_size))
38+
watermark_text = watermark_text.set_fps(fps)
39+
watermark_text = watermark_text.set_duration(video_clip.reader.duration)
40+
watermark_text = watermark_text.margin(left=10, right=10, bottom=2, opacity=0)
41+
watermark_text = watermark_text.set_position(("bottom"))
42+
43+
# cvc = CompositeVideoClip([watermark_text], size=video_clip.size)
44+
# cvc = cvc.set_duration(video_clip.reader.duration)
45+
# cvc = cvc.set_fps(fps)
46+
# cvc = cvc.set_audio(None)
47+
48+
overlay_clip = CompositeVideoClip([video_clip, watermark_text], size=video_clip.size)
49+
overlay_clip = overlay_clip.set_duration(video_clip.reader.duration)
50+
overlay_clip = overlay_clip.set_fps(fps)
51+
overlay_clip = overlay_clip.set_audio(None)
52+
53+
og_audio = AudioFileClip(og_audio_path)
54+
overlay_clip = overlay_clip.set_audio(og_audio)
55+
56+
57+
final_clip = concatenate_videoclips([intro_text, overlay_clip])
58+
final_clip.write_videofile(final_video_path, codec='libx264', audio_codec="aac")

tutorial-reference/Day 15/Pipfile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[[source]]
2+
name = "pypi"
3+
url = "https://pypi.org/simple"
4+
verify_ssl = true
5+
6+
[dev-packages]
7+
8+
[packages]
9+
moviepy = "*"
10+
pillow = "*"
11+
12+
[requires]
13+
python_version = "3.8"

tutorial-reference/Day 15/conf.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import os
2+
3+
ABS_PATH = os.path.abspath(__file__)
4+
BASE_DIR = os.path.dirname(ABS_PATH)
5+
DATA_DIR = os.path.join(BASE_DIR, "data")
6+
SAMPLE_DIR = os.path.join(DATA_DIR, "samples")
7+
SAMPLE_INPUTS = os.path.join(SAMPLE_DIR, "inputs")
8+
SAMPLE_OUTPUTS = os.path.join(SAMPLE_DIR, 'outputs')
17.2 MB
6.8 MB
Binary file not shown.

0 commit comments

Comments
 (0)