-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmake_movie.py
127 lines (107 loc) · 4.51 KB
/
make_movie.py
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
117
118
119
120
121
122
123
124
125
126
127
# -*- coding: utf-8 -*-
import argparse
from moviepy.editor import VideoFileClip, CompositeVideoClip
from moviepy.audio.fx import volumex
import os
from pprint import pprint
import subprocess
import sys
from lib.collection_utils import *
from lib.image_utils import *
from lib.io_utils import *
from lib.math_utils import *
from lib.processing_utils import *
from lib.video_utils import *
# input
parser = argparse.ArgumentParser()
parser.add_argument('-in', dest="INPUT_FILE", default="path/to/manifest.csv", help="Input csv instruction file")
parser.add_argument('-dir', dest="MEDIA_DIRECTORY", default="output/", help="Input markdown file")
parser.add_argument('-pad0', dest="PAD_START", default=2.0, type=float, help="Padding at start in s")
parser.add_argument('-pad1', dest="PAD_END", default=1.0, type=float, help="Padding at end in s")
parser.add_argument('-volume', dest="VOLUME", type=float, default=1.5, help="Adjust volume")
parser.add_argument('-out', dest="OUTPUT_FILE", default="output/trailer.mp4", help="Output media file")
parser.add_argument('-quality', dest="QUALITY", default="high", help="High quality is slower")
parser.add_argument('-probe', dest="PROBE", action="store_true", help="Just view statistics")
a = parser.parse_args()
aa = vars(a)
fieldNames, instructions = readCsv(a.INPUT_FILE)
makeDirectories([a.OUTPUT_FILE])
if len(instructions) <= 0:
print("No instructions in %s" % a.INPUT_FILE)
sys.exit()
instructions = prependAll(instructions, ("filename", a.MEDIA_DIRECTORY))
# instructions = instructions[:4]
# load videos
sequenceDur = 0
for i, step in enumerate(instructions):
prev = False if i < 1 else instructions[i-1]
# get duration from file
if step["clip_dur"] < 0:
instructions[i]["clip_dur"] = getDurationFromFile(step["filename"], accurate=True)
step = instructions[i]
# offset start if we are crossfading
if step["crossfade"] > 0:
instructions[i]["offset_start"] = -step["fade_in"]
step = instructions[i]
# inherit start from previous if not defined
if step["clip_start"] < 0 and prev:
instructions[i]["clip_start"] = prev["clip_start"] + prev["clip_dur"] + step["offset_start"]
step = instructions[i]
instructions[i]["start"] = a.PAD_START + sequenceDur + step["offset_start"]
sequenceDur += step["offset_start"] + step["clip_dur"]
duration = a.PAD_START + sequenceDur + a.PAD_END
print("Total time: %s" % formatSeconds(duration))
# determine video properties from the first clip
testClip = VideoFileClip(instructions[0]["filename"])
width, height = testClip.size
fps = testClip.fps
# testClip = testClip.subclip(20, 6)
# testClip.reader.close()
# del testClip
print("Creating movie at %s x %s with %s fps" % (width, height, fps))
if a.PROBE:
sys.exit()
clips = []
time = a.PAD_START
steps = len(instructions)
for i, step in enumerate(instructions):
clip = VideoFileClip(step["filename"])
vdur = clip.duration
cstart = step["clip_start"]
cdur = step["clip_dur"]
if (cstart + cdur) > vdur:
print("%s not long enough: %s > %s" % (step["filename"], (cstart + cdur), vdur))
sys.exit()
# make a clip if we are not taking the whole thing
# print("%s, %s" % (step["clip_start"], step["clip_dur"]))
if cstart > 0 or cdur < vdur:
clip = clip.subclip(step["clip_start"], step["clip_start"]+step["clip_dur"])
clip = clip.set_position((0, 0))
clip = clip.set_start(step["start"])
nextStep = False if i >= steps-1 else instructions[i+1]
# cross fade in
if step["crossfade"] > 0 and step["fade_in"] > 0:
clip = clip.crossfadein(step["fade_in"])
elif step["fade_in"] > 0:
clip = clip.fadein(step["fade_in"])
# cross fade out if next clip is cross fading in
if nextStep and nextStep["crossfade"] > 0 and nextStep["fade_in"] > 0:
clip = clip.crossfadeout(nextStep["fade_in"])
elif step["fade_out"] > 0:
clip = clip.fadeout(step["fade_out"])
# fade in/out audio
if step["fade_in"] > 0:
clip = clip.audio_fadein(step["fade_in"])
if step["fade_out"] > 0:
clip = clip.audio_fadeout(step["fade_out"])
clips.append(clip)
printProgress(i+1, steps)
video = CompositeVideoClip(clips, size=(width, height))
video = video.set_duration(duration)
if a.VOLUME != 1.0:
video = video.volumex(a.VOLUME)
if a.QUALITY == "high":
video.write_videofile(a.OUTPUT_FILE, preset="slow", audio_bitrate="256k", audio_fps=48000, bitrate="19820k")
else:
video.write_videofile(a.OUTPUT_FILE)
print("Wrote %s to file" % a.OUTPUT_FILE)