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

Issue #596: Add support for closing clips. #608

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/getting_started/efficient_moviepy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ When to close() a clip

When you create some types of clip instances - e.g. ``VideoFileClip`` or ``AudioFileClip`` - MoviePy creates a subprocess and locks the file. In order to release those resources when you are finished you should call the ``close()`` method.

This is more important for more complex applications and it particularly important when running on Windows. While Python's garbage collector should eventually clean it the resources for you, clsing them makes them available earlier.
This is more important for more complex applications and it particularly important when running on Windows. While Python's garbage collector should eventually clean it the resources for you, closing them makes them available earlier.

However, if you close a clip too early, methods on the clip (and any clips derived from it) become unsafe.

Expand Down Expand Up @@ -134,4 +134,4 @@ For instance, when you are editing an animated GIF and want to check that it loo

ipython_display(my_clip, autoplay=1, loop=1)

Importantly, ``ipython_display`` actually embeds the clips physically in your notebook. The advantage is that you can move the notebook or put it online and the videos will work. The drawback is that the file size of the notebook can become very large. Depending on your browser, re-computing and displaying at video many times can take some place in the cache and the RAM (it will only be a problem for intensive uses). Restarting your browser solves the problem.
Importantly, ``ipython_display`` actually embeds the clips physically in your notebook. The advantage is that you can move the notebook or put it online and the videos will work. The drawback is that the file size of the notebook can become very large. Depending on your browser, re-computing and displaying at video many times can take some place in the cache and the RAM (it will only be a problem for intensive uses). Restarting your browser solves the problem.
1 change: 0 additions & 1 deletion moviepy/Clip.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class Clip:
this case their duration will be ``None``.

"""

# prefix for all temporary video and audio files.
# You can overwrite it with
# >>> Clip._TEMP_FILES_PREFIX = "temp_"
Expand Down
20 changes: 20 additions & 0 deletions moviepy/audio/io/ffmpeg_audiowriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,32 @@ def __del__(self):

# Support the Context Manager protocol, to ensure that resources are cleaned up.

def close(self):
if self.proc:
self.proc.stdin.close()
self.proc.stdin = None
if self.proc.stderr is not None:
self.proc.stderr.close()
self.proc.stdee = None
# If this causes deadlocks, consider terminating instead.
self.proc.wait()
self.proc = None

def __del__(self):
# If the garbage collector comes, make sure the subprocess is terminated.
self.close()

# Support the Context Manager protocol, to ensure that resources are cleaned up.

def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, traceback):
self.close()

def __exit__(self, exc_type, exc_value, traceback):
Copy link
Collaborator

@mgaitan mgaitan Apr 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is repeated, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Well spotted. That is an error. (It is of no consequence, but one should be deleted.)

self.close()


@requires_duration
def ffmpeg_audiowrite(clip, filename, fps, nbytes, buffersize,
Expand Down
1 change: 1 addition & 0 deletions moviepy/video/io/VideoFileClip.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def __init__(self, filename, has_mask=False,

# Make a reader
pix_fmt = "rgba" if has_mask else "rgb24"

self.reader = FFMPEG_VideoReader(filename, pix_fmt=pix_fmt,
target_resolution=target_resolution,
resize_algo=resize_algorithm,
Expand Down
1 change: 0 additions & 1 deletion tests/test_PR.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ def test_PR_529():
with VideoFileClip("media/fire2.mp4") as video_clip:
assert video_clip.rotation == 180


def test_PR_610():
"""
Test that the max fps of the video clips is used for the composite video clip
Expand Down
1 change: 1 addition & 0 deletions tests/test_resourcereleasedemo.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,6 @@ def test_failure_to_release_file():

remove(local_video_filename)
print("You are not running Windows, because that worked.")

except OSError: # More specifically, PermissionError in Python 3.
print("Yes, on Windows this fails.")
4 changes: 2 additions & 2 deletions tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"""Tool tests meant to be run with pytest. Taken from PR #121 (grimley517)."""
import sys
import time
import pytest

import moviepy.tools as tools
import pytest


def test_ext():
Expand Down Expand Up @@ -70,4 +70,4 @@ def test_5():
assert file == b""

if __name__ == '__main__':
pytest.main()
pytest.main()