Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pick highest fps when concatenating #416

Merged
10 commits merged into from
Feb 27, 2017
5 changes: 2 additions & 3 deletions moviepy/audio/io/readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ def skip_chunk(self,chunksize):


def read_chunk(self,chunksize):
# chunksize is not being autoconverted from float to int
chunksize = int(round(chunksize))
L = self.nchannels*chunksize*self.nbytes
s = self.proc.stdout.read(L)
dt = {1: 'int8',2:'int16',4:'int32'}[self.nbytes]
Expand Down Expand Up @@ -238,6 +240,3 @@ def buffer_around(self,framenumber):

def __del__(self):
self.close_proc()



36 changes: 15 additions & 21 deletions moviepy/video/compositing/concatenate.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
def concatenate_videoclips(clips, method="chain", transition=None,
bg_color=None, ismask=False, padding = 0):
""" Concatenates several video clips

Returns a video clip made by clip by concatenating several video clips.
(Concatenated means that they will be played one after another).

There are two methods:

- method="chain": will produce a clip that simply outputs
Expand All @@ -38,56 +38,50 @@ def concatenate_videoclips(clips, method="chain", transition=None,
will be transparent if mask=True, else it will be of the
color specified by ``bg_color``.

If all clips with a fps attribute have the same fps, it becomes the fps of
the result.
The clip with the highest FPS will be the FPS of the result clip.

Parameters
-----------

clips
A list of video clips which must all have their ``duration``
attributes set.

method
"chain" or "compose": see above.

transition
A clip that will be played between each two clips of the list.

bg_color
Only for method='compose'. Color of the background.
Set to None for a transparent clip

padding
Only for method='compose'. Duration during two consecutive clips.
Note that for negative padding, a clip will partly play at the same
time as the clip it follows (negative padding is cool for clips who fade
in on one another). A non-null padding automatically sets the method to
`compose`.

"""

if transition is not None:
l = [[v, transition] for v in clips[:-1]]
clips = reduce(lambda x, y: x + y, l) + [clips[-1]]
transition = None


tt = np.cumsum([0] + [c.duration for c in clips])

sizes = [v.size for v in clips]


w = max([r[0] for r in sizes])
h = max([r[1] for r in sizes])

tt = np.maximum(0, tt + padding*np.arange(len(tt)))

if method == "chain":
def make_frame(t):
i = max([i for i, e in enumerate(tt) if e <= t])
return clips[i].get_frame(t - tt[i])

result = VideoClip(ismask = ismask, make_frame = make_frame)
if any([c.mask is not None for c in clips]):
masks = [c.mask if (c.mask is not None) else
Expand All @@ -96,26 +90,26 @@ def make_frame(t):
for c in clips]
result.mask = concatenate_videoclips(masks, method="chain", ismask=True)
result.clips = clips


elif method == "compose":
result = CompositeVideoClip( [c.set_start(t).set_pos('center')
for (c, t) in zip(clips, tt)],
size = (w, h), bg_color=bg_color, ismask=ismask)

result.tt = tt

result.start_times = tt[:-1]
result.start, result.duration, result.end = 0, tt[-1] , tt[-1]

audio_t = [(c.audio,t) for c,t in zip(clips,tt) if c.audio is not None]
if len(audio_t)>0:
result.audio = CompositeAudioClip([a.set_start(t)
for a,t in audio_t])

fps_list = list(set([c.fps for c in clips if hasattr(c,'fps')]))
if len(fps_list)==1:
result.fps= fps_list[0]
fpss = [c.fps for c in clips if hasattr(c,'fps') and c.fps is not None]
if len(fpss) == 0:
result.fps = None
else:
result.fps = max(fpss)

return result

Expand Down