Skip to content

Commit

Permalink
Fix conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
mondeja committed Jan 20, 2021
2 parents 8dc224a + a378771 commit 71bf30f
Show file tree
Hide file tree
Showing 19 changed files with 304 additions and 163 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added <!-- for new features -->
- Support for `copy.copy(clip)` and `copy.deepcopy(clip)` with same behaviour as `clip.copy()` [\#1442](https://github.com/Zulko/moviepy/pull/1442)
- `audio.fx.multiply_stereo_volume` to control volume by audio channels [\#1424](https://github.com/Zulko/moviepy/pull/1424)
- Support for retrieve clip frames number using `clip.n_frames` [\#1471](https://github.com/Zulko/moviepy/pull/1471)
- `video.io.ffmpeg_reader.ffmpeg_parse_infos` returns data from all streams by FFmpeg inputs in attribute `inputs` [\#1466](https://github.com/Zulko/moviepy/pull/1466)
- `video.io.ffmpeg_reader.ffmpeg_parse_infos` returns metadata of the container in attribute `metadata` [\#1466](https://github.com/Zulko/moviepy/pull/1466)

Expand All @@ -22,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Changed recommended import from `import moviepy.editor` to `import moviepy`. This change is fully backwards compatible [\#1340](https://github.com/Zulko/moviepy/pull/1340)
- Renamed `audio.fx.volumex` to `audio.fx.multiply_volume` [\#1424](https://github.com/Zulko/moviepy/pull/1424)
- Renamed `cols_widths` argument of `clips_array` function by `cols_heights` [\#1465](https://github.com/Zulko/moviepy/pull/1465)
- `video_nframes` attribute of dictionary returned from `ffmpeg_parse_infos` renamed to `video_n_frames` [\#1471](https://github.com/Zulko/moviepy/pull/1471)

### Deprecated <!-- for soon-to-be removed features -->
- `moviepy.video.fx.all` and `moviepy.audio.fx.all`. Use the fx method directly from the clip instance or import the fx function from `moviepy.video.fx` and `moviepy.audio.fx`. [\#1105](https://github.com/Zulko/moviepy/pull/1105)
Expand All @@ -38,6 +40,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed calling `audio_normalize` on a clip with no sound causing `ZeroDivisionError` [\#1401](https://github.com/Zulko/moviepy/pull/1401)
- Fixed `freeze` FX was freezing at time minus 1 second as the end [\#1461](https://github.com/Zulko/moviepy/pull/1461)
- `AudioClip.max_volume(stereo=True)` now can return more than 2 channels [\#1464](https://github.com/Zulko/moviepy/pull/1464)
- Fixed `Clip.cutout` transformation not being applied to audio [\#1468](https://github.com/Zulko/moviepy/pull/1468)
- Fixed arguments inconsistency in `video.tools.drawing.color_gradient` [\#1467](https://github.com/Zulko/moviepy/pull/1467)
- Fixed `fps` not defined in `CompositeAudioClip` at initialization [\#1462](https://github.com/Zulko/moviepy/pull/1462)


## [v2.0.0.dev2](https://github.com/zulko/moviepy/tree/v2.0.0.dev2) (2020-10-05)
Expand Down
7 changes: 3 additions & 4 deletions docs/examples/quick_recipes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,8 @@ Getting the average frame of a video

from moviepy import VideoFileClip, ImageClip
clip = VideoFileClip("video.mp4")
fps= 1.0 # take one frame per second
nframes = clip.duration*fps # total number of frames used
total_image = sum(clip.iter_frames(fps,dtype=float,logger='bar'))
average_image = ImageClip(total_image/ nframes)
fps = 1.0 # take one frame per second
total_image = sum(clip.iter_frames(fps, dtype=float, logger='bar'))
average_image = ImageClip(total_image / clip.n_frames)
average_image.save_frame("average_test.png")

9 changes: 7 additions & 2 deletions examples/logo.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import numpy as np

from moviepy import *
from moviepy.editor import *

w, h = moviesize = (720, 380)
WIDTH, HEIGHT = (720, 380)
WHITE = (255, 255, 255)

duration = 1

Expand All @@ -13,7 +14,10 @@ def f(t, size, a=np.pi / 3, thickness=20):
center = [int(t * w / duration), h / 2]
return biGradientScreen(size, center, v, 0.6, 0.0)

logo = ImageClip("docs/_static/logo.png").with_duration(2).on_color((WIDTH, HEIGHT), color=WHITE, pos="center").with_fps(60)
logo.write_videofile("test.mp4")

"""
logo = ImageClip("../../videos/logo_descr.png").resize(width=w / 2).with_mask(mask)
screen = logo.on_color(moviesize, color=(0, 0, 0), pos="center")
Expand All @@ -25,3 +29,4 @@ def f(t, size, a=np.pi / 3, thickness=20):
cc = CompositeVideoClip([im.set_pos(2 * ["center"]), shade], size=moviesize)
cc.subclip(0, duration).write_videofile("moviepy_logo.avi", fps=24)
"""
12 changes: 6 additions & 6 deletions examples/the_end.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from moviepy import *
from moviepy.editor import *
from moviepy.video.tools.drawing import circle

clip = (
VideoFileClip("../../videos/badl-0006.mov", audio=False).subclip(26, 31).add_mask()
VideoFileClip("media/chaplin.mp4", audio=False).add_mask()
)

w, h = clip.size
Expand All @@ -19,9 +19,9 @@


the_end = TextClip(
"The End", font="Amiri-bold", color="white", font_size=70
).with_duration(clip.duration)
"The End", font="Amiri-bold", color="white", font_size=70,
).with_duration(clip.duration).with_position("center")

final = CompositeVideoClip([the_end.set_pos("center"), clip], size=clip.size)
final = CompositeVideoClip([the_end, clip], size=clip.size)

final.write_videofile("../../theEnd.avi")
final.preview()
8 changes: 2 additions & 6 deletions moviepy/Clip.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,6 @@ def subclip(self, start_time=0, end_time=None):

return new_clip

@apply_to_mask
@apply_to_audio
@convert_parameter_to_seconds(["start_time", "end_time"])
def cutout(self, start_time, end_time):
"""
Expand All @@ -429,15 +427,13 @@ def cutout(self, start_time, end_time):
"""

new_clip = self.time_transform(
lambda t: t + (t >= start_time) * (end_time - start_time)
lambda t: t + (t >= start_time) * (end_time - start_time),
apply_to=["audio", "mask"],
)

if self.duration is not None:

return new_clip.with_duration(self.duration - (end_time - start_time))

else:

return new_clip

@requires_duration
Expand Down
80 changes: 48 additions & 32 deletions moviepy/audio/AudioClip.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import numbers
import os

import numpy as np
Expand Down Expand Up @@ -308,53 +309,68 @@ class CompositeAudioClip(AudioClip):
clips
List of audio clips, which may start playing at different times or
together. If all have their ``duration`` attribute set, the
duration of the composite clip is computed automatically.
together, depends on their ``start`` attributes. If all have their
``duration`` attribute set, the duration of the composite clip is
computed automatically.
"""

def __init__(self, clips):

Clip.__init__(self)
self.clips = clips
self.nchannels = max(clip.nchannels for clip in self.clips)

ends = [clip.end for clip in self.clips]
self.nchannels = max([clip.nchannels for clip in self.clips])
if not any([(end is None) for end in ends]):
self.duration = max(ends)
self.end = max(ends)
# self.duration is setted at AudioClip
duration = None
for end in self.ends:
if end is None:
break
duration = max(end, duration or 0)

def make_frame(t):
# self.fps is setted at AudioClip
fps = None
for clip in self.clips:
if hasattr(clip, "fps") and isinstance(clip.fps, numbers.Number):
fps = max(clip.fps, fps or 0)

played_parts = [clip.is_playing(t) for clip in self.clips]
super().__init__(duration=duration, fps=fps)

sounds = [
clip.get_frame(t - clip.start) * np.array([part]).T
for clip, part in zip(self.clips, played_parts)
if (part is not False)
]
@property
def starts(self):
return (clip.start for clip in self.clips)

if isinstance(t, np.ndarray):
zero = np.zeros((len(t), self.nchannels))
@property
def ends(self):
return (clip.end for clip in self.clips)

else:
zero = np.zeros(self.nchannels)
def make_frame(self, t):
played_parts = [clip.is_playing(t) for clip in self.clips]

return zero + sum(sounds)
sounds = [
clip.get_frame(t - clip.start) * np.array([part]).T
for clip, part in zip(self.clips, played_parts)
if (part is not False)
]

self.make_frame = make_frame
if isinstance(t, np.ndarray):
zero = np.zeros((len(t), self.nchannels))
else:
zero = np.zeros(self.nchannels)

return zero + sum(sounds)


def concatenate_audioclips(clips):
"""
The clip with the highest FPS will be the FPS of the result clip.
"""
durations = [clip.duration for clip in clips]
timings = np.cumsum([0] + durations) # start times, and end time.
newclips = [clip.with_start(t) for clip, t in zip(clips, timings)]
"""Concatenates one AudioClip after another, in the order that are passed
to ``clips`` parameter.
Parameters
----------
result = CompositeAudioClip(newclips).with_duration(timings[-1])
clips
List of audio clips, which will be played one after other.
"""
# start, end/start2, end2/start3... end
starts_end = np.cumsum([0, *[clip.duration for clip in clips]])
newclips = [clip.with_start(t) for clip, t in zip(clips, starts_end[:-1])]

fpss = [clip.fps for clip in clips if getattr(clip, "fps", None)]
result.fps = max(fpss) if fpss else None
return result
return CompositeAudioClip(newclips).with_duration(starts_end[-1])
9 changes: 4 additions & 5 deletions moviepy/audio/io/ffmpeg_audiowriter.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import os
import subprocess as sp

import proglog

from moviepy.config import FFMPEG_BINARY
from moviepy.decorators import requires_duration
from moviepy.tools import cross_platform_popen_params


class FFMPEG_AudioWriter:
Expand Down Expand Up @@ -82,10 +82,9 @@ def __init__(
cmd.extend(ffmpeg_params)
cmd.extend([filename])

popen_params = {"stdout": sp.DEVNULL, "stderr": logfile, "stdin": sp.PIPE}

if os.name == "nt":
popen_params["creationflags"] = 0x08000000
popen_params = cross_platform_popen_params(
{"stdout": sp.DEVNULL, "stderr": logfile, "stdin": sp.PIPE}
)

self.proc = sp.Popen(cmd, **popen_params)

Expand Down
25 changes: 12 additions & 13 deletions moviepy/audio/io/readers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import os
import subprocess as sp
import warnings

import numpy as np

from moviepy.config import FFMPEG_BINARY
from moviepy.video.io.ffmpeg_reader import ffmpeg_parse_infos
from moviepy.tools import cross_platform_popen_params


class FFMPEG_AudioReader:
Expand Down Expand Up @@ -63,8 +63,8 @@ def __init__(
self.infos = infos
self.proc = None

self.nframes = int(self.fps * self.duration)
self.buffersize = min(self.nframes + 1, buffersize)
self.n_frames = int(self.fps * self.duration)
self.buffersize = min(self.n_frames + 1, buffersize)
self.buffer = None
self.buffer_startframe = 1
self.initialize()
Expand Down Expand Up @@ -107,15 +107,14 @@ def initialize(self, start_time=0):
]
)

popen_params = {
"bufsize": self.buffersize,
"stdout": sp.PIPE,
"stderr": sp.PIPE,
"stdin": sp.DEVNULL,
}

if os.name == "nt":
popen_params["creationflags"] = 0x08000000
popen_params = cross_platform_popen_params(
{
"bufsize": self.buffersize,
"stdout": sp.PIPE,
"stderr": sp.PIPE,
"stdin": sp.DEVNULL,
}
)

self.proc = sp.Popen(cmd, **popen_params)

Expand Down Expand Up @@ -215,7 +214,7 @@ def get_frame(self, tt):
else:

ind = int(self.fps * tt)
if ind < 0 or ind > self.nframes: # out of time: return 0
if ind < 0 or ind > self.n_frames: # out of time: return 0
return np.zeros(self.nchannels)

if not (0 <= (ind - self.buffer_startframe) < len(self.buffer)):
Expand Down
12 changes: 5 additions & 7 deletions moviepy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from pathlib import Path
import subprocess as sp

from moviepy.tools import cross_platform_popen_params


if os.name == "nt":
import winreg as wr
Expand All @@ -20,13 +22,9 @@

def try_cmd(cmd):
try:
popen_params = {"stdout": sp.PIPE, "stderr": sp.PIPE, "stdin": sp.DEVNULL}

# This was added so that no extra unwanted window opens on windows
# when the child process is created
if os.name == "nt":
popen_params["creationflags"] = 0x08000000

popen_params = cross_platform_popen_params(
{"stdout": sp.PIPE, "stderr": sp.PIPE, "stdin": sp.DEVNULL}
)
proc = sp.Popen(cmd, **popen_params)
proc.communicate()
except Exception as err:
Expand Down
10 changes: 10 additions & 0 deletions moviepy/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ def requires_duration(func, clip, *args, **kwargs):
return func(clip, *args, **kwargs)


@decorator.decorator
def requires_fps(func, clip, *args, **kwargs):
""" Raise an error if the clip has no fps."""

if not hasattr(clip, "fps") or clip.fps is None:
raise ValueError("Attribute 'fps' not set")
else:
return func(clip, *args, **kwargs)


@decorator.decorator
def audio_video_fx(func, clip, *args, **kwargs):
"""Use an audio function on a video/audio clip
Expand Down
20 changes: 16 additions & 4 deletions moviepy/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@
import proglog


def cross_platform_popen_params(popen_params):
"""Wrap with this function a dictionary of ``subprocess.Popen`` kwargs and
will be ready to work without unexpected behaviours in any platform.
Currently, the implementation will add to them:
- ``creationflags=0x08000000``: no extra unwanted window opens on Windows
when the child process is created. Only added on Windows.
"""
if os.name == "nt":
popen_params["creationflags"] = 0x08000000
return popen_params


def subprocess_call(cmd, logger="bar"):
"""Executes the given subprocess command.
Expand All @@ -16,10 +29,9 @@ def subprocess_call(cmd, logger="bar"):
logger = proglog.default_bar_logger(logger)
logger(message="Moviepy - Running:\n>>> " + " ".join(cmd))

popen_params = {"stdout": sp.DEVNULL, "stderr": sp.PIPE, "stdin": sp.DEVNULL}

if os.name == "nt":
popen_params["creationflags"] = 0x08000000
popen_params = cross_platform_popen_params(
{"stdout": sp.DEVNULL, "stderr": sp.PIPE, "stdin": sp.DEVNULL}
)

proc = sp.Popen(cmd, **popen_params)

Expand Down
Loading

0 comments on commit 71bf30f

Please sign in to comment.