diff --git a/ffmpeg/_run.py b/ffmpeg/_run.py index c9cbb7ce9058ef06fc9947779ed817d8ed5e52cb..f66b19a7fdc55058ee41adc33fd0089aa78aa778 100644 --- a/ffmpeg/_run.py +++ b/ffmpeg/_run.py @@ -327,3 +327,11 @@ def run( __all__ = ['compile', 'Error', 'get_args', 'run', 'run_async'] + +try: + from ._run_asyncio import * +except (SyntaxError, ImportError): + pass +else: + from . import _run_asyncio + __all__ += _run_asyncio.__all__ diff --git a/ffmpeg/_run_asyncio.py b/ffmpeg/_run_asyncio.py new file mode 100644 index 0000000000000000000000000000000000000000..7ae7335c3c2e63be7e31d1aa6d88447ad11288d6 --- /dev/null +++ b/ffmpeg/_run_asyncio.py @@ -0,0 +1,47 @@ +import asyncio + +from ._run import output_operator +from ._run import * + + +@output_operator() +@asyncio.coroutine +def run_asyncio( + stream_spec, + cmd='ffmpeg', + pipe_stdin=False, + pipe_stdout=False, + pipe_stderr=False, + quiet=False, + overwrite_output=False, +): + """Asynchronously invoke ffmpeg in asyncio sync/await style and return coroutine. + Have the same possibilities as `run_async` call. + + Args: + pipe_stdin: if True, connect pipe to subprocess stdin (to be + used with ``pipe:`` ffmpeg inputs). + pipe_stdout: if True, connect pipe to subprocess stdout (to be + used with ``pipe:`` ffmpeg outputs). + pipe_stderr: if True, connect pipe to subprocess stderr. + quiet: shorthand for setting ``capture_stdout`` and + ``capture_stderr``. + + Returns: + A Process instance as a coroutine + """ + + args = compile(stream_spec, cmd, overwrite_output=overwrite_output) + stdin_stream = asyncio.subprocess.PIPE if pipe_stdin else None + stdout_stream = asyncio.subprocess.PIPE if pipe_stdout or quiet else None + stderr_stream = asyncio.subprocess.PIPE if pipe_stderr or quiet else None + + result = yield from asyncio.create_subprocess_exec( + *args, + stdin=stdin_stream, + stdout=stdout_stream, + stderr=stderr_stream + ) + return result + +__all__ = ['run_asyncio'] diff --git a/ffmpeg/tests/_test_asyncio.py b/ffmpeg/tests/_test_asyncio.py new file mode 100644 index 0000000000000000000000000000000000000000..623c62016e4791741ddfcd4fa446197f4e8aeb79 --- /dev/null +++ b/ffmpeg/tests/_test_asyncio.py @@ -0,0 +1,33 @@ +import ffmpeg +import asyncio + +from .test_ffmpeg import TEST_INPUT_FILE1 + + +def test_run_asyncio(): + @asyncio.coroutine + def test_async(): + process = yield from ( + ffmpeg + .input(TEST_INPUT_FILE1) + .output('pipe:', format='rawvideo', pix_fmt='rgb24')['v'] + .run_asyncio(pipe_stdout=True, quiet=False) + ) + + video_frame_size = 320 * 240 * 3 # Note: RGB24 == 3 bytes per pixel. 320x240 - video size + + total_bytes = 0 + + while True: + frame_bytes = yield from process.stdout.read(video_frame_size) + if len(frame_bytes) == 0: + break + else: + total_bytes += len(frame_bytes) + + yield from process.wait() + + assert total_bytes == 48153600, 'Incorrect size of the output frames' + + loop = asyncio.get_event_loop() + loop.run_until_complete(test_async()) diff --git a/ffmpeg/tests/test_ffmpeg.py b/ffmpeg/tests/test_ffmpeg.py index 51ee258726884fb44400f1eee5b9a920aed95bed..9663819f05ae463b969aeacdaba617f2b1948eda 100644 --- a/ffmpeg/tests/test_ffmpeg.py +++ b/ffmpeg/tests/test_ffmpeg.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals + from builtins import bytes from builtins import range from builtins import str @@ -782,3 +783,7 @@ def test__multi_output_edge_label_order(): out1, out2 = get_filter_complex_outputs(flt_cmpl, 'scale2ref') assert out1 == get_filter_complex_input(flt_cmpl, 'scale') assert out2 == get_filter_complex_input(flt_cmpl, 'hflip') + + +if sys.version_info >= (3, 4): + from ._test_asyncio import test_run_asyncio