Hello community,
here is the log from the commit of package python-imageio-ffmpeg for
openSUSE:Factory checked in at 2020-04-15 20:06:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-imageio-ffmpeg (Old)
and /work/SRC/openSUSE:Factory/.python-imageio-ffmpeg.new.2738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-imageio-ffmpeg"
Wed Apr 15 20:06:31 2020 rev:2 rq:792769 version:0.4.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-imageio-ffmpeg/python-imageio-ffmpeg.changes
2019-05-22 11:08:41.690613817 +0200
+++
/work/SRC/openSUSE:Factory/.python-imageio-ffmpeg.new.2738/python-imageio-ffmpeg.changes
2020-04-15 20:08:04.670169743 +0200
@@ -1,0 +2,11 @@
+Thu Apr 9 14:12:14 UTC 2020 - Marketa Calabkova <[email protected]>
+
+- Update to 0.4.1
+ * The default value for ffmpeg_timeout is now zero, e.g. just wait for
ffmpeg.
+ * Added bits_per_pixel parameter to read_frames.
+ * Official support for Python 3.8.
+ * Improved handling of interrupts during reading/writing/closing-down.
+ * Allow the ffmpeg_timeout arg in write_frames() to be None.
+ * Don't prevent sigint propagation for ffmpeg call in
count_frames_and_secs().
+
+-------------------------------------------------------------------
Old:
----
imageio-ffmpeg-0.3.0.tar.gz
New:
----
imageio-ffmpeg-0.4.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-imageio-ffmpeg.spec ++++++
--- /var/tmp/diff_new_pack.kLrLPH/_old 2020-04-15 20:08:05.186170095 +0200
+++ /var/tmp/diff_new_pack.kLrLPH/_new 2020-04-15 20:08:05.186170095 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-imageio-ffmpeg
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -12,18 +12,19 @@
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
+#
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-imageio-ffmpeg
-Version: 0.3.0
+Version: 0.4.1
Release: 0
-License: BSD-2-Clause
Summary: FFMPEG wrapper for Python
-Url: https://github.com/imageio/imageio-ffmpeg
+License: BSD-2-Clause
Group: Development/Languages/Python
+URL: https://github.com/imageio/imageio-ffmpeg
Source:
https://files.pythonhosted.org/packages/source/i/imageio-ffmpeg/imageio-ffmpeg-%{version}.tar.gz
BuildRequires: %{python_module pip > 19}
BuildRequires: %{python_module setuptools}
@@ -32,7 +33,6 @@
BuildRequires: python-rpm-macros
Requires: ffmpeg-4
BuildArch: noarch
-
%python_subpackages
%description
++++++ imageio-ffmpeg-0.3.0.tar.gz -> imageio-ffmpeg-0.4.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/imageio-ffmpeg-0.3.0/PKG-INFO
new/imageio-ffmpeg-0.4.1/PKG-INFO
--- old/imageio-ffmpeg-0.3.0/PKG-INFO 2019-04-12 11:08:07.000000000 +0200
+++ new/imageio-ffmpeg-0.4.1/PKG-INFO 2020-02-24 15:11:03.000000000 +0100
@@ -1,11 +1,11 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: imageio-ffmpeg
-Version: 0.3.0
+Version: 0.4.1
Summary: FFMPEG wrapper for Python
Home-page: https://github.com/imageio/imageio-ffmpeg
Author: imageio contributors
Author-email: [email protected]
-License: (new) BSD
+License: BSD-2-Clause
Download-URL: http://pypi.python.org/pypi/imageio-ffmpeg
Description: FFMPEG wrapper for Python.
@@ -33,4 +33,6 @@
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
Provides: imageio_ffmpeg
+Requires-Python: >=3.4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/imageio-ffmpeg-0.3.0/README.md
new/imageio-ffmpeg-0.4.1/README.md
--- old/imageio-ffmpeg-0.3.0/README.md 2019-04-12 11:07:51.000000000 +0200
+++ new/imageio-ffmpeg-0.4.1/README.md 2020-02-24 14:13:52.000000000 +0100
@@ -1,6 +1,7 @@
# imageio-ffmpeg
[](https://travis-ci.org/imageio/imageio-ffmpeg)
+[](https://pypi.python.org/pypi/imageio-ffmpeg/)
FFMPEG wrapper for Python
@@ -45,7 +46,7 @@
`IMAGEIO_FFMPEG_EXE` environment variable if needed.
-## Usage
+## Example usage
The `imageio_ffmpeg` library provides low level functionality to read
and write video data, using Python generators:
@@ -67,6 +68,8 @@
writer.close() # don't forget this
```
+(Also see the API section further down.)
+
## How it works
@@ -77,20 +80,45 @@
the code itself too. In contrast, [PyAV](https://github.com/mikeboers/PyAV)
wraps ffmpeg at the C level.
+Note that because of how `imageio-ffmpeg` works, `read_frames()` and
+`write_frames()` only accept file names, and not file (like) objects.
+
+
+
+## imageio-ffmpeg for enterprise
+
+Available as part of the Tidelift Subscription
+
+The maintainers of imageio-ffmpeg and thousands of other packages are working
with Tidelift to deliver commercial support and maintenance for the open source
dependencies you use to build your applications. Save time, reduce risk, and
improve code health, while paying the maintainers of the exact dependencies you
use. [Learn
more.](https://tidelift.com/subscription/pkg/pypi-imageio-ffmpeg?utm_source=pypi-imageio-ffmpeg&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
+
+
+## Security contact information
+
+To report a security vulnerability, please use the
+[Tidelift security contact](https://tidelift.com/security).
+Tidelift will coordinate the fix and disclosure.
+
## API
```py
-def read_frames(path, pix_fmt="rgb24", bpp=3, input_params=None,
output_params=None):
+def read_frames(
+ path,
+ pix_fmt="rgb24",
+ bpp=None,
+ input_params=None,
+ output_params=None,
+ bits_per_pixel=None,
+):
"""
Create a generator to iterate over the frames in a video file.
It first yields a small metadata dictionary that contains:
- * ffmpeg_version: the ffmpeg version is use (as a string).
- * codec: a hint about the codec used to encode the video, e.g. "h264"
- * source_size: the width and height of the encoded video frames
- * size: the width and height of the frames that will be produced
+ * ffmpeg_version: the ffmpeg version in use (as a string).
+ * codec: a hint about the codec used to encode the video, e.g. "h264".
+ * source_size: the width and height of the encoded video frames.
+ * size: the width and height of the frames that will be produced.
* fps: the frames per second. Can be zero if it could not be detected.
* duration: duration in seconds. Can be zero if it could not be detected.
@@ -113,13 +141,16 @@
print(len(frame))
Parameters:
- path (str): the file to write to.
+ path (str): the filename of the file to read from.
pix_fmt (str): the pixel format of the frames to be read.
The default is "rgb24" (frames are uint8 RGB images).
- bpp (int): The number of bytes per pixel in the output frames.
- This depends on the given pix_fmt. Default is 3 (RGB).
input_params (list): Additional ffmpeg input command line parameters.
output_params (list): Additional ffmpeg output command line parameters.
+ bits_per_pixel (int): The number of bits per pixel in the output
frames.
+ This depends on the given pix_fmt. Default is 24 (RGB)
+ bpp (int): DEPRECATED, USE bits_per_pixel INSTEAD. The number of bytes
per pixel in the output frames.
+ This depends on the given pix_fmt. Some pixel formats like yuv420p
have 12 bits per pixel
+ and cannot be set in bytes as integer. For this reason the bpp
argument is deprecated.
"""
```
@@ -135,6 +166,7 @@
codec=None,
macro_block_size=16,
ffmpeg_log_level="warning",
+ ffmpeg_timeout=0,
input_params=None,
output_params=None,
):
@@ -154,7 +186,7 @@
gen.close() # don't forget this
Parameters:
- path (str): the file to write to.
+ path (str): the filename to write to.
size (tuple): the width and height of the frames.
pix_fmt_in (str): the pixel format of incoming frames.
E.g. "gray", "gray8a", "rgb24", or "rgba". Default "rgb24".
@@ -167,7 +199,10 @@
macro_block_size (int): You probably want to align the size of frames
to this value to avoid image resizing. Default 16. Can be set
to 1 to avoid block alignment, though this is not recommended.
- ffmpeg_log_level (str): The ffmpeg logging level.
+ ffmpeg_log_level (str): The ffmpeg logging level. Default "warning".
+ ffmpeg_timeout (float): Timeout in seconds to wait for ffmpeg process
+ to finish. Value of 0 will wait forever (default). The time that
+ ffmpeg needs depends on CPU speed, compression, and frame size.
input_params (list): Additional ffmpeg input command line parameters.
output_params (list): Additional ffmpeg output command line parameters.
"""
@@ -188,7 +223,7 @@
```py
def get_ffmpeg_exe():
"""
- Get the ffmpeg executable file. This can be the binary defined by
+ Get the ffmpeg executable file. This can be the binary defined by
the IMAGEIO_FFMPEG_EXE environment variable, the binary distributed
with imageio-ffmpeg, an ffmpeg binary installed with conda, or the
system ffmpeg (in that order). A RuntimeError is raised if no valid
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/imageio-ffmpeg-0.3.0/imageio_ffmpeg/_definitions.py
new/imageio-ffmpeg-0.4.1/imageio_ffmpeg/_definitions.py
--- old/imageio-ffmpeg-0.3.0/imageio_ffmpeg/_definitions.py 2019-04-12
11:07:51.000000000 +0200
+++ new/imageio-ffmpeg-0.4.1/imageio_ffmpeg/_definitions.py 2020-02-24
15:10:39.000000000 +0100
@@ -1,7 +1,7 @@
import sys
import struct
-__version__ = "0.3.0"
+__version__ = "0.4.1"
def get_platform():
@@ -10,6 +10,8 @@
return "linux{}".format(bits)
elif sys.platform.startswith("win"):
return "win{}".format(bits)
+ elif sys.platform.startswith("cygwin"):
+ return "win{}".format(bits)
elif sys.platform.startswith("darwin"):
return "osx{}".format(bits)
else: # pragma: no cover
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/imageio-ffmpeg-0.3.0/imageio_ffmpeg/_io.py
new/imageio-ffmpeg-0.4.1/imageio_ffmpeg/_io.py
--- old/imageio-ffmpeg-0.3.0/imageio_ffmpeg/_io.py 2019-04-12
11:07:51.000000000 +0200
+++ new/imageio-ffmpeg-0.4.1/imageio_ffmpeg/_io.py 2020-02-24
15:10:39.000000000 +0100
@@ -1,9 +1,9 @@
import sys
import time
-import signal
+import pathlib
import subprocess
-from ._utils import get_ffmpeg_exe, logger
+from ._utils import get_ffmpeg_exe, _popen_kwargs, logger
from ._parsing import LogCatcher, parse_ffmpeg_header, cvsecs
@@ -31,11 +31,14 @@
"""
# https://stackoverflow.com/questions/2017843/fetch-frame-count-with-ffmpeg
- assert isinstance(path, str), "Video path must be a string"
+ if isinstance(path, pathlib.PurePath):
+ path = str(path)
+ if not isinstance(path, str):
+ raise TypeError("Video path must be a string or pathlib.Path.")
cmd = [_get_exe(), "-i", path, "-map", "0:v:0", "-c", "copy", "-f",
"null", "-"]
try:
- out = subprocess.check_output(cmd, stderr=subprocess.STDOUT,
shell=ISWIN)
+ out = subprocess.check_output(cmd, stderr=subprocess.STDOUT,
**_popen_kwargs())
except subprocess.CalledProcessError as err:
out = err.output.decode(errors="ignore")
raise RuntimeError("FFMEG call failed with
{}:\n{}".format(err.returncode, out))
@@ -60,16 +63,23 @@
raise RuntimeError("Could not get number of frames") # pragma: no cover
-def read_frames(path, pix_fmt="rgb24", bpp=3, input_params=None,
output_params=None):
+def read_frames(
+ path,
+ pix_fmt="rgb24",
+ bpp=None,
+ input_params=None,
+ output_params=None,
+ bits_per_pixel=None,
+):
"""
Create a generator to iterate over the frames in a video file.
It first yields a small metadata dictionary that contains:
- * ffmpeg_version: the ffmpeg version is use (as a string).
- * codec: a hint about the codec used to encode the video, e.g. "h264"
- * source_size: the width and height of the encoded video frames
- * size: the width and height of the frames that will be produced
+ * ffmpeg_version: the ffmpeg version in use (as a string).
+ * codec: a hint about the codec used to encode the video, e.g. "h264".
+ * source_size: the width and height of the encoded video frames.
+ * size: the width and height of the frames that will be produced.
* fps: the frames per second. Can be zero if it could not be detected.
* duration: duration in seconds. Can be zero if it could not be detected.
@@ -92,27 +102,34 @@
print(len(frame))
Parameters:
- path (str): the file to write to.
+ path (str): the filename of the file to read from.
pix_fmt (str): the pixel format of the frames to be read.
The default is "rgb24" (frames are uint8 RGB images).
- bpp (int): The number of bytes per pixel in the output frames.
- This depends on the given pix_fmt. Default is 3 (RGB).
input_params (list): Additional ffmpeg input command line parameters.
output_params (list): Additional ffmpeg output command line parameters.
+ bits_per_pixel (int): The number of bits per pixel in the output
frames.
+ This depends on the given pix_fmt. Default is 24 (RGB)
+ bpp (int): DEPRECATED, USE bits_per_pixel INSTEAD. The number of bytes
per pixel in the output frames.
+ This depends on the given pix_fmt. Some pixel formats like yuv420p
have 12 bits per pixel
+ and cannot be set in bytes as integer. For this reason the bpp
argument is deprecated.
"""
# ----- Input args
- assert isinstance(path, str), "Video path must be a string"
+ if isinstance(path, pathlib.PurePath):
+ path = str(path)
+ if not isinstance(path, str):
+ raise TypeError("Video path must be a string or pathlib.Path.")
# Note: Dont check whether it exists. The source could be e.g. a camera.
pix_fmt = pix_fmt or "rgb24"
bpp = bpp or 3
+ bits_per_pixel = bits_per_pixel or bpp * 8
input_params = input_params or []
output_params = output_params or []
assert isinstance(pix_fmt, str), "pix_fmt must be a string"
- assert isinstance(bpp, int), "bpp must be an int"
+ assert isinstance(bits_per_pixel, int), "bpp and bits_per_pixel must be an
int"
assert isinstance(input_params, list), "input_params must be a list"
assert isinstance(output_params, list), "output_params must be a list"
@@ -129,18 +146,25 @@
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
- shell=ISWIN,
+ **_popen_kwargs(prevent_sigint=True)
)
log_catcher = LogCatcher(p.stderr)
+ # Init policy by which to terminate ffmpeg. May be set to "kill" later.
+ stop_policy = "timeout" # not wait; ffmpeg should be able to quit quickly
+
+ # Enter try block directly after opening the process.
+ # We terminate ffmpeg in the finally clause.
+ # Generators are automatically closed when they get deleted,
+ # so the finally block is guaranteed to run.
try:
# ----- Load meta data
# Wait for the log catcher to get the meta information
etime = time.time() + 10.0
- while (not log_catcher.header) and time.time() < etime:
+ while log_catcher.is_alive() and not log_catcher.header and
time.time() < etime:
time.sleep(0.01)
# Check whether we have the information
@@ -157,15 +181,20 @@
# ----- Read frames
w, h = meta["size"]
- framesize = w * h * bpp
+ framesize_bits = w * h * bits_per_pixel
+ framesize_bytes = framesize_bits / 8
+ assert (
+ framesize_bytes.is_integer()
+ ), "incorrect bits_per_pixel, framesize in bytes must be an int"
+ framesize_bytes = int(framesize_bytes)
framenr = 0
while True:
framenr += 1
try:
bb = bytes()
- while len(bb) < framesize:
- extra_bytes = p.stdout.read(framesize - len(bb))
+ while len(bb) < framesize_bytes:
+ extra_bytes = p.stdout.read(framesize_bytes - len(bb))
if not extra_bytes:
if len(bb) == 0:
return
@@ -181,31 +210,55 @@
fmt = "Could not read frame {}:\n{}\n=== stderr ===\n{}"
raise RuntimeError(fmt.format(framenr, err1, err2))
+ except GeneratorExit:
+ # Note that GeneratorExit does not inherit from Exception but
BaseException
+ pass
+
+ except Exception:
+ # Normal exceptions fall through
+ raise
+
+ except BaseException:
+ # Detect KeyboardInterrupt / SystemExit: don't wait for ffmpeg to quit
+ stop_policy = "kill"
+ raise
+
finally:
- # Generators are automatically closed when they get deleted,
- # so this code is almost guaranteed to run.
+ # Make sure that ffmpeg is terminated.
if p.poll() is None:
# Ask ffmpeg to quit
try:
- if True:
- p.communicate(b"q")
- else: # pragma: no cover
- # I read somewhere that modern ffmpeg on Linux prefers a
- # "ctrl-c", but tests so far suggests sending q is better.
- p.send_signal(signal.SIGINT)
+ # I read somewhere that modern ffmpeg on Linux prefers a
+ # "ctrl-c", but tests so far suggests sending q is more robust.
+ # > p.send_signal(signal.SIGINT)
+ # Sending q via communicate works, but can hang (see #17)
+ # > p.communicate(b"q")
+ # So let's do similar to what communicate does, but without
+ # reading stdout (which may block). It looks like only closing
+ # stdout is enough (tried Windows+Linux), but let's play safe.
+ # Found that writing to stdin can cause "Invalid argument" on
+ # Windows # and "Broken Pipe" on Unix.
+ # p.stdin.write(b"q") # commented out in v0.4.1
+ p.stdout.close()
+ p.stdin.close()
except Exception as err: # pragma: no cover
- logger.warning("Error while attempting stop ffmpeg: " +
str(err))
+ logger.warning("Error while attempting stop ffmpeg (r): " +
str(err))
- # Wait for it to stop
- etime = time.time() + 1.5
- while time.time() < etime and p.poll() is None:
- time.sleep(0.01)
-
- # Grr, we have to kill it
- if p.poll() is None: # pragma: no cover
- logger.warning("We had to kill ffmpeg to stop it.")
+ if stop_policy == "timeout":
+ # Wait until timeout, produce a warning and kill if it still
exists
+ try:
+ etime = time.time() + 1.5
+ while time.time() < etime and p.poll() is None:
+ time.sleep(0.01)
+ finally:
+ if p.poll() is None: # pragma: no cover
+ logger.warning("We had to kill ffmpeg to stop it.")
+ p.kill()
+
+ else: # stop_policy == "kill"
+ # Just kill it
p.kill()
@@ -220,7 +273,7 @@
codec=None,
macro_block_size=16,
ffmpeg_log_level="warning",
- ffmpeg_timeout=20.0,
+ ffmpeg_timeout=None,
input_params=None,
output_params=None,
):
@@ -240,7 +293,7 @@
gen.close() # don't forget this
Parameters:
- path (str): the file to write to.
+ path (str): the filename to write to.
size (tuple): the width and height of the frames.
pix_fmt_in (str): the pixel format of incoming frames.
E.g. "gray", "gray8a", "rgb24", or "rgba". Default "rgb24".
@@ -255,15 +308,18 @@
to 1 to avoid block alignment, though this is not recommended.
ffmpeg_log_level (str): The ffmpeg logging level. Default "warning".
ffmpeg_timeout (float): Timeout in seconds to wait for ffmpeg process
- to finish. Value of 0 will wait forever. The time that ffmpeg needs
- depends on CPU speed, compression, and frame size. Default 20.0.
+ to finish. Value of 0 or None will wait forever (default). The
time that
+ ffmpeg needs depends on CPU speed, compression, and frame size.
input_params (list): Additional ffmpeg input command line parameters.
output_params (list): Additional ffmpeg output command line parameters.
"""
# ----- Input args
- assert isinstance(path, str), "Video path must be a string"
+ if isinstance(path, pathlib.PurePath):
+ path = str(path)
+ if not isinstance(path, str):
+ raise TypeError("Video path must be a string or pathlib.Path.")
# The pix_fmt_out yuv420p is the best for the outpur to work in
# QuickTime and most other players. These players only support
@@ -281,6 +337,7 @@
ffmpeg_log_level = ffmpeg_log_level or "warning"
input_params = input_params or []
output_params = output_params or []
+ ffmpeg_timeout = ffmpeg_timeout or 0
floatish = float, int
if isinstance(size, (tuple, list)):
@@ -376,20 +433,31 @@
# Launch process
p = subprocess.Popen(
- cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None,
shell=ISWIN
+ cmd,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=None,
+ **_popen_kwargs(prevent_sigint=True)
)
- # For Windows, set `shell=True` in sp.Popen to prevent popup
- # of a command line window in frozen applications.
# Note that directing stderr to a pipe on windows will cause ffmpeg
# to hang if the buffer is not periodically cleared using
# StreamCatcher or other means.
# Setting bufsize to 0 or a small value does not seem to have much effect
- # (at least on Windows). I suspect that ffmpeg buffers # multiple frames
- # (before encoding in a batch).
+ # (tried on Windows and Linux). I suspect that ffmpeg buffers
+ # multiple frames (before encoding in a batch).
+
+ # Init policy by which to terminate ffmpeg. May be set to "kill" later.
+ stop_policy = "timeout"
+ if not ffmpeg_timeout:
+ stop_policy = "wait"
# ----- Write frames
+ # Enter try block directly after opening the process.
+ # We terminate ffmpeg in the finally clause.
+ # Generators are automatically closed when they get deleted,
+ # so the finally block is guaranteed to run.
try:
# Just keep going until the generator.close() is called (raises
GeneratorExit).
@@ -398,7 +466,7 @@
while True:
# Get frame
- bb = (yield)
+ bb = yield
# framesize = size[0] * size[1] * depth * bpp
# assert isinstance(bb, bytes), "Frame must be send as bytes"
@@ -420,29 +488,55 @@
nframes += 1
except GeneratorExit:
+ # Note that GeneratorExit does not inherit from Exception but
BaseException
+ # Detect premature closing
if nframes == 0:
logger.warning("No frames have been written; the written video is
invalid.")
+
+ except Exception:
+ # Normal exceptions fall through
+ raise
+
+ except BaseException:
+ # Detect KeyboardInterrupt / SystemExit: don't wait for ffmpeg to quit
+ stop_policy = "kill"
+ raise
+
finally:
+ # Make sure that ffmpeg is terminated.
if p.poll() is None:
- # Ask ffmpeg to quit - and wait for it to finish writing the file.
- # Depending on the frame size and encoding this can take a few
- # seconds (sometimes 10-20). Since a user may get bored and hit
- # Ctrl-C, we wrap this in a try-except.
- waited = False
+ # Tell ffmpeg that we're done
try:
+ p.stdin.close()
+ except Exception as err: # pragma: no cover
+ logger.warning("Error while attempting stop ffmpeg (w): " +
str(err))
+
+ if stop_policy == "timeout":
+ # Wait until timeout, produce a warning and kill if it still
exists
+ try:
+ etime = time.time() + ffmpeg_timeout
+ while (time.time() < etime) and p.poll() is None:
+ time.sleep(0.01)
+ finally:
+ if p.poll() is None: # pragma: no cover
+ logger.warning(
+ "We had to kill ffmpeg to stop it. "
+ + "Consider increasing ffmpeg_timeout, "
+ + "or setting it to zero (no timeout)."
+ )
+ p.kill()
+
+ elif stop_policy == "wait":
+ # Wait forever, kill if it if we're interrupted
try:
- p.stdin.close()
- except Exception: # pragma: no cover
- pass
- etime = time.time() + ffmpeg_timeout
- while (not ffmpeg_timeout or time.time() < etime) and p.poll()
is None:
- time.sleep(0.01)
- waited = True
- finally:
- # Grr, we have to kill it
- if p.poll() is None: # pragma: no cover
- more = " Consider increasing ffmpeg_timeout." if waited
else ""
- logger.warning("We had to kill ffmpeg to stop it." + more)
- p.kill()
+ while p.poll() is None:
+ time.sleep(0.01)
+ finally: # the above can raise e.g. by ctrl-c or systemexit
+ if p.poll() is None: # pragma: no cover
+ p.kill()
+
+ else: # stop_policy == "kill":
+ # Just kill it
+ p.kill()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/imageio-ffmpeg-0.3.0/imageio_ffmpeg/_utils.py
new/imageio-ffmpeg-0.4.1/imageio_ffmpeg/_utils.py
--- old/imageio-ffmpeg-0.3.0/imageio_ffmpeg/_utils.py 2019-04-12
11:07:51.000000000 +0200
+++ new/imageio-ffmpeg-0.4.1/imageio_ffmpeg/_utils.py 2020-02-24
15:10:39.000000000 +0100
@@ -1,8 +1,8 @@
import os
-from pkg_resources import resource_filename
import sys
-import subprocess
import logging
+import subprocess
+from pkg_resources import resource_filename
from ._definitions import get_platform, FNAME_PER_PLATFORM
@@ -11,7 +11,7 @@
def get_ffmpeg_exe():
"""
- Get the ffmpeg executable file. This can be the binary defined by
+ Get the ffmpeg executable file. This can be the binary defined by
the IMAGEIO_FFMPEG_EXE environment variable, the binary distributed
with imageio-ffmpeg, an ffmpeg binary installed with conda, or the
system ffmpeg (in that order). A RuntimeError is raised if no valid
@@ -52,11 +52,35 @@
)
+def _popen_kwargs(prevent_sigint=False):
+ startupinfo = None
+ preexec_fn = None
+ creationflags = 0
+ if sys.platform.startswith("win"):
+ # Stops executable from flashing on Windows (see #22)
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ if prevent_sigint:
+ # Prevent propagation of sigint (see #4)
+ # https://stackoverflow.com/questions/5045771
+ if sys.platform.startswith("win"):
+ creationflags = 0x00000200
+ else:
+ preexec_fn = os.setpgrp # the _pre_exec does not seem to work
+ return {
+ "startupinfo": startupinfo,
+ "creationflags": creationflags,
+ "preexec_fn": preexec_fn,
+ }
+
+
def _is_valid_exe(exe):
cmd = [exe, "-version"]
try:
with open(os.devnull, "w") as null:
- subprocess.check_call(cmd, stdout=null, stderr=subprocess.STDOUT)
+ subprocess.check_call(
+ cmd, stdout=null, stderr=subprocess.STDOUT, **_popen_kwargs()
+ )
return True
except (OSError, ValueError, subprocess.CalledProcessError):
return False
@@ -67,7 +91,9 @@
Get the version of the used ffmpeg executable (as a string).
"""
exe = get_ffmpeg_exe()
- line = subprocess.check_output([exe, "-version"]).split(b"\n", 1)[0]
+ line = subprocess.check_output([exe, "-version"], **_popen_kwargs()).split(
+ b"\n", 1
+ )[0]
line = line.decode(errors="ignore").strip()
version = line.split("version", 1)[-1].lstrip().split(" ", 1)[0].strip()
return version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/imageio-ffmpeg-0.3.0/imageio_ffmpeg.egg-info/PKG-INFO
new/imageio-ffmpeg-0.4.1/imageio_ffmpeg.egg-info/PKG-INFO
--- old/imageio-ffmpeg-0.3.0/imageio_ffmpeg.egg-info/PKG-INFO 2019-04-12
11:08:07.000000000 +0200
+++ new/imageio-ffmpeg-0.4.1/imageio_ffmpeg.egg-info/PKG-INFO 2020-02-24
15:11:03.000000000 +0100
@@ -1,11 +1,11 @@
-Metadata-Version: 1.1
+Metadata-Version: 1.2
Name: imageio-ffmpeg
-Version: 0.3.0
+Version: 0.4.1
Summary: FFMPEG wrapper for Python
Home-page: https://github.com/imageio/imageio-ffmpeg
Author: imageio contributors
Author-email: [email protected]
-License: (new) BSD
+License: BSD-2-Clause
Download-URL: http://pypi.python.org/pypi/imageio-ffmpeg
Description: FFMPEG wrapper for Python.
@@ -33,4 +33,6 @@
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
Provides: imageio_ffmpeg
+Requires-Python: >=3.4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/imageio-ffmpeg-0.3.0/setup.cfg
new/imageio-ffmpeg-0.4.1/setup.cfg
--- old/imageio-ffmpeg-0.3.0/setup.cfg 2019-04-12 11:08:07.000000000 +0200
+++ new/imageio-ffmpeg-0.4.1/setup.cfg 2020-02-24 15:11:03.000000000 +0100
@@ -1,5 +1,4 @@
[egg_info]
-tag_date = 0
tag_build =
-tag_svn_revision = 0
+tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/imageio-ffmpeg-0.3.0/setup.py
new/imageio-ffmpeg-0.4.1/setup.py
--- old/imageio-ffmpeg-0.3.0/setup.py 2019-04-12 11:07:51.000000000 +0200
+++ new/imageio-ffmpeg-0.4.1/setup.py 2020-02-24 14:13:52.000000000 +0100
@@ -48,7 +48,7 @@
version=__version__,
author="imageio contributors",
author_email="[email protected]",
- license="(new) BSD",
+ license="BSD-2-Clause",
url="https://github.com/imageio/imageio-ffmpeg",
download_url="http://pypi.python.org/pypi/imageio-ffmpeg",
keywords="video ffmpeg",
@@ -58,7 +58,7 @@
provides=["imageio_ffmpeg"],
python_requires=">=3.4",
setup_requires=["pip>19"],
- install_requires=[], # todo: maybe numpy
+ install_requires=[],
packages=["imageio_ffmpeg"],
package_dir={"imageio_ffmpeg": "imageio_ffmpeg"},
package_data={"imageio_ffmpeg": ["binaries/*.*"]},
@@ -79,5 +79,6 @@
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
],
)