mirror of
https://github.com/kkroening/ffmpeg-python.git
synced 2025-04-02 10:02:48 +08:00
Add input/output support in run
command; update docs
This commit is contained in:
parent
90561c7a8a
commit
ac57e2df13
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@ dist/
|
||||
ffmpeg/tests/sample_data/out*.mp4
|
||||
ffmpeg_python.egg-info/
|
||||
venv*
|
||||
build/
|
||||
|
@ -50,12 +50,14 @@
|
||||
<div class="genindex-jumpbox">
|
||||
<a href="#C"><strong>C</strong></a>
|
||||
| <a href="#D"><strong>D</strong></a>
|
||||
| <a href="#E"><strong>E</strong></a>
|
||||
| <a href="#F"><strong>F</strong></a>
|
||||
| <a href="#G"><strong>G</strong></a>
|
||||
| <a href="#H"><strong>H</strong></a>
|
||||
| <a href="#I"><strong>I</strong></a>
|
||||
| <a href="#M"><strong>M</strong></a>
|
||||
| <a href="#O"><strong>O</strong></a>
|
||||
| <a href="#P"><strong>P</strong></a>
|
||||
| <a href="#R"><strong>R</strong></a>
|
||||
| <a href="#S"><strong>S</strong></a>
|
||||
| <a href="#T"><strong>T</strong></a>
|
||||
@ -67,6 +69,8 @@
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#ffmpeg.colorchannelmixer">colorchannelmixer() (in module ffmpeg)</a>
|
||||
</li>
|
||||
<li><a href="index.html#ffmpeg.compile">compile() (in module ffmpeg)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
@ -89,6 +93,14 @@
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="E">E</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#ffmpeg.Error">Error</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="F">F</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
@ -97,6 +109,8 @@
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#ffmpeg.filter_">filter_() (in module ffmpeg)</a>
|
||||
</li>
|
||||
<li><a href="index.html#ffmpeg.filter_multi_output">filter_multi_output() (in module ffmpeg)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
@ -151,6 +165,14 @@
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="P">P</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="index.html#ffmpeg.probe">probe() (in module ffmpeg)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
</tr></table>
|
||||
|
||||
<h2 id="R">R</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
|
@ -313,6 +313,21 @@ and arguments to ffmpeg verbatim.</p>
|
||||
<p><code class="docutils literal"><span class="pre">ffmpeg.input('in.mp4').filter_('hflip').output('out.mp4').run()</span></code></p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="ffmpeg.filter_multi_output">
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">filter_multi_output</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>filter_name</em>, <em>*args</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.filter_multi_output" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Apply custom filter with one or more outputs.</p>
|
||||
<p>This is the same as <code class="docutils literal"><span class="pre">filter_</span></code> except that the filter can produce more than one output.</p>
|
||||
<p>To reference an output stream, use either the <code class="docutils literal"><span class="pre">.stream</span></code> operator or bracket shorthand:</p>
|
||||
<p class="rubric">Example</p>
|
||||
<p><code class="docutils literal"><span class="pre">`</span>
|
||||
<span class="pre">split</span> <span class="pre">=</span> <span class="pre">ffmpeg.input('in.mp4').filter_multi_output('split')</span>
|
||||
<span class="pre">split0</span> <span class="pre">=</span> <span class="pre">split.stream(0)</span>
|
||||
<span class="pre">split1</span> <span class="pre">=</span> <span class="pre">split[1]</span>
|
||||
<span class="pre">ffmpeg.concat(split0,</span> <span class="pre">split1).output('out.mp4').run()</span>
|
||||
<span class="pre">`</span></code></p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="ffmpeg.hflip">
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">hflip</code><span class="sig-paren">(</span><em>stream</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.hflip" title="Permalink to this definition">¶</a></dt>
|
||||
@ -479,6 +494,9 @@ for single input image.</li>
|
||||
<dt id="ffmpeg.input">
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">input</code><span class="sig-paren">(</span><em>filename</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.input" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Input file URL (ffmpeg <code class="docutils literal"><span class="pre">-i</span></code> option)</p>
|
||||
<p>Any supplied kwargs are passed to ffmpeg verbatim (e.g. <code class="docutils literal"><span class="pre">t=20</span></code>,
|
||||
<code class="docutils literal"><span class="pre">f='mp4'</span></code>, <code class="docutils literal"><span class="pre">acodec='pcm'</span></code>, etc.).</p>
|
||||
<p>To tell ffmpeg to read from stdin, use <code class="docutils literal"><span class="pre">pipe:</span></code> as the filename.</p>
|
||||
<p>Official documentation: <a class="reference external" href="https://ffmpeg.org/ffmpeg.html#Main-options">Main options</a></p>
|
||||
</dd></dl>
|
||||
|
||||
@ -490,8 +508,17 @@ for single input image.</li>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="ffmpeg.output">
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">output</code><span class="sig-paren">(</span><em>stream</em>, <em>filename</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.output" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">output</code><span class="sig-paren">(</span><em>*streams_and_filename</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.output" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Output file URL</p>
|
||||
<dl class="docutils">
|
||||
<dt>Syntax:</dt>
|
||||
<dd><cite>ffmpeg.output(stream1[, stream2, stream3…], filename, **ffmpeg_args)</cite></dd>
|
||||
</dl>
|
||||
<p>If multiple streams are provided, they are mapped to the same
|
||||
output.</p>
|
||||
<p>Any supplied kwargs are passed to ffmpeg verbatim (e.g. <code class="docutils literal"><span class="pre">t=20</span></code>,
|
||||
<code class="docutils literal"><span class="pre">f='mp4'</span></code>, <code class="docutils literal"><span class="pre">acodec='pcm'</span></code>, etc.).</p>
|
||||
<p>To tell ffmpeg to write to stdout, use <code class="docutils literal"><span class="pre">pipe:</span></code> as the filename.</p>
|
||||
<p>Official documentation: <a class="reference external" href="https://ffmpeg.org/ffmpeg.html#Synopsis">Synopsis</a></p>
|
||||
</dd></dl>
|
||||
|
||||
@ -502,24 +529,53 @@ for single input image.</li>
|
||||
<p>Official documentation: <a class="reference external" href="https://ffmpeg.org/ffmpeg.html#Main-options">Main options</a></p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="ffmpeg.compile">
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">compile</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>cmd=u'ffmpeg'</em>, <em>overwrite_output=False</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.compile" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Build command-line for invoking ffmpeg.</p>
|
||||
<p>The <a class="reference internal" href="#ffmpeg.run" title="ffmpeg.run"><code class="xref py py-meth docutils literal"><span class="pre">run()</span></code></a> function uses this to build the commnad line
|
||||
arguments and should work in most cases, but calling this function
|
||||
directly is useful for debugging or if you need to invoke ffmpeg
|
||||
manually for whatever reason.</p>
|
||||
<p>This is the same as calling <a class="reference internal" href="#ffmpeg.get_args" title="ffmpeg.get_args"><code class="xref py py-meth docutils literal"><span class="pre">get_args()</span></code></a> except that it also
|
||||
includes the <code class="docutils literal"><span class="pre">ffmpeg</span></code> command as the first argument.</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="exception">
|
||||
<dt id="ffmpeg.Error">
|
||||
<em class="property">exception </em><code class="descclassname">ffmpeg.</code><code class="descname">Error</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>stdout</em>, <em>stderr</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.Error" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Bases: <code class="xref py py-class docutils literal"><span class="pre">exceptions.Exception</span></code></p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="ffmpeg.get_args">
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">get_args</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>overwrite_output=False</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.get_args" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Get command-line arguments for ffmpeg.</p>
|
||||
<dd><p>Build command-line arguments to be passed to ffmpeg.</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="ffmpeg.run">
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">run</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>cmd=u'ffmpeg'</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.run" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Run ffmpeg on node graph.</p>
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">run</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>cmd=u'ffmpeg'</em>, <em>capture_stdout=False</em>, <em>capture_stderr=False</em>, <em>input=None</em>, <em>quiet=False</em>, <em>overwrite_output=False</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.run" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Ivoke ffmpeg for the supplied node graph.</p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><strong>**kwargs</strong> – keyword-arguments passed to <code class="docutils literal"><span class="pre">get_args()</span></code> (e.g. <code class="docutils literal"><span class="pre">overwrite_output=True</span></code>).</td>
|
||||
<tr class="field-odd field"><th class="field-name">Parameters:</th><td class="field-body"><ul class="first last simple">
|
||||
<li><strong>capture_stdout</strong> – if True, capture stdout (to be used with
|
||||
<code class="docutils literal"><span class="pre">pipe:</span></code> ffmpeg outputs).</li>
|
||||
<li><strong>capture_stderr</strong> – if True, capture stderr.</li>
|
||||
<li><strong>quiet</strong> – shorthand for setting <code class="docutils literal"><span class="pre">capture_stdout</span></code> and <code class="docutils literal"><span class="pre">capture_stderr</span></code>.</li>
|
||||
<li><strong>input</strong> – text to be sent to stdin (to be used with <code class="docutils literal"><span class="pre">pipe:</span></code>
|
||||
ffmpeg inputs)</li>
|
||||
<li><strong>**kwargs</strong> – keyword-arguments passed to <code class="docutils literal"><span class="pre">get_args()</span></code> (e.g.
|
||||
<code class="docutils literal"><span class="pre">overwrite_output=True</span></code>).</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Returns: (out, err) tuple containing captured stdout and stderr data.</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
@ -527,6 +583,23 @@ for single input image.</li>
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">view</code><span class="sig-paren">(</span><em>stream_spec</em>, <em>**kwargs</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.view" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="function">
|
||||
<dt id="ffmpeg.probe">
|
||||
<code class="descclassname">ffmpeg.</code><code class="descname">probe</code><span class="sig-paren">(</span><em>filename</em><span class="sig-paren">)</span><a class="headerlink" href="#ffmpeg.probe" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Run ffprobe on the specified file and return a JSON representation of the output.</p>
|
||||
<table class="docutils field-list" frame="void" rules="none">
|
||||
<col class="field-name" />
|
||||
<col class="field-body" />
|
||||
<tbody valign="top">
|
||||
<tr class="field-odd field"><th class="field-name">Raises:</th><td class="field-body"><a class="reference internal" href="#ffmpeg.Error" title="ffmpeg.Error"><code class="xref py py-class docutils literal"><span class="pre">ffmpeg.Error</span></code></a> – if ffprobe returns a non-zero exit code,
|
||||
an <a class="reference internal" href="#ffmpeg.Error" title="ffmpeg.Error"><code class="xref py py-class docutils literal"><span class="pre">Error</span></code></a> is returned with a generic error message.
|
||||
The stderr output can be retrieved by accessing the
|
||||
<code class="docutils literal"><span class="pre">stderr</span></code> property of the exception.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</dd></dl>
|
||||
|
||||
</div>
|
||||
<div class="section" id="indices-and-tables">
|
||||
<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline">¶</a></h1>
|
||||
|
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -16,6 +16,11 @@ from .nodes import (
|
||||
def input(filename, **kwargs):
|
||||
"""Input file URL (ffmpeg ``-i`` option)
|
||||
|
||||
Any supplied kwargs are passed to ffmpeg verbatim (e.g. ``t=20``,
|
||||
``f='mp4'``, ``acodec='pcm'``, etc.).
|
||||
|
||||
To tell ffmpeg to read from stdin, use ``pipe:`` as the filename.
|
||||
|
||||
Official documentation: `Main options <https://ffmpeg.org/ffmpeg.html#Main-options>`__
|
||||
"""
|
||||
kwargs['filename'] = filename
|
||||
@ -57,7 +62,13 @@ def output(*streams_and_filename, **kwargs):
|
||||
Syntax:
|
||||
`ffmpeg.output(stream1[, stream2, stream3...], filename, **ffmpeg_args)`
|
||||
|
||||
If multiple streams are provided, they are mapped to the same output.
|
||||
If multiple streams are provided, they are mapped to the same
|
||||
output.
|
||||
|
||||
Any supplied kwargs are passed to ffmpeg verbatim (e.g. ``t=20``,
|
||||
``f='mp4'``, ``acodec='pcm'``, etc.).
|
||||
|
||||
To tell ffmpeg to write to stdout, use ``pipe:`` as the filename.
|
||||
|
||||
Official documentation: `Synopsis <https://ffmpeg.org/ffmpeg.html#Synopsis>`__
|
||||
"""
|
||||
|
16
ffmpeg/_probe.py
Executable file → Normal file
16
ffmpeg/_probe.py
Executable file → Normal file
@ -1,29 +1,25 @@
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
|
||||
class ProbeException(Exception):
|
||||
def __init__(self, stderr_output):
|
||||
super(ProbeException, self).__init__('ffprobe error')
|
||||
self.stderr_output = stderr_output
|
||||
from ._run import Error
|
||||
|
||||
|
||||
def probe(filename):
|
||||
"""Run ffprobe on the specified file and return a JSON representation of the output.
|
||||
|
||||
Raises:
|
||||
ProbeException: if ffprobe returns a non-zero exit code, a ``ProbeException`` is returned with a generic error
|
||||
message. The stderr output can be retrieved by accessing the ``stderr_output`` property of the exception.
|
||||
:class:`ffmpeg.Error`: if ffprobe returns a non-zero exit code,
|
||||
an :class:`Error` is returned with a generic error message.
|
||||
The stderr output can be retrieved by accessing the
|
||||
``stderr`` property of the exception.
|
||||
"""
|
||||
args = ['ffprobe', '-show_format', '-show_streams', '-of', 'json', filename]
|
||||
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
out, err = p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise ProbeException(err)
|
||||
raise Error(err)
|
||||
return json.loads(out.decode('utf-8'))
|
||||
|
||||
|
||||
__all__ = [
|
||||
'probe',
|
||||
'ProbeException',
|
||||
]
|
||||
|
@ -1,13 +1,13 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from builtins import str
|
||||
from past.builtins import basestring
|
||||
from .dag import get_outgoing_edges, topo_sort
|
||||
from functools import reduce
|
||||
from ._utils import basestring
|
||||
from builtins import str
|
||||
from functools import reduce
|
||||
from past.builtins import basestring
|
||||
import copy
|
||||
import operator
|
||||
import subprocess as _subprocess
|
||||
import subprocess
|
||||
|
||||
from ._ffmpeg import (
|
||||
input,
|
||||
@ -23,6 +23,14 @@ from .nodes import (
|
||||
)
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
def __init__(self, stream_spec, stdout, stderr):
|
||||
super(Error, self).__init__('ffmpeg error (see stderr output for detail)')
|
||||
self.stream_spec = stream_spec
|
||||
self.stdout = stdout
|
||||
self.stderr = stderr
|
||||
|
||||
|
||||
def _convert_kwargs_to_cmd_line_args(kwargs):
|
||||
args = []
|
||||
for k in sorted(kwargs.keys()):
|
||||
@ -80,8 +88,9 @@ def _allocate_filter_stream_names(filter_nodes, outgoing_edge_maps, stream_name_
|
||||
for upstream_label, downstreams in list(outgoing_edge_map.items()):
|
||||
if len(downstreams) > 1:
|
||||
# TODO: automatically insert `splits` ahead of time via graph transformation.
|
||||
raise ValueError('Encountered {} with multiple outgoing edges with same upstream label {!r}; a '
|
||||
'`split` filter is probably required'.format(upstream_node, upstream_label))
|
||||
raise ValueError(
|
||||
'Encountered {} with multiple outgoing edges with same upstream label {!r}; a '
|
||||
'`split` filter is probably required'.format(upstream_node, upstream_label))
|
||||
stream_name_map[upstream_node, upstream_label] = 's{}'.format(stream_count)
|
||||
stream_count += 1
|
||||
|
||||
@ -122,7 +131,7 @@ def _get_output_args(node, stream_name_map):
|
||||
|
||||
@output_operator()
|
||||
def get_args(stream_spec, overwrite_output=False):
|
||||
"""Get command-line arguments for ffmpeg."""
|
||||
"""Build command-line arguments to be passed to ffmpeg."""
|
||||
nodes = get_stream_spec_nodes(stream_spec)
|
||||
args = []
|
||||
# TODO: group nodes together, e.g. `-i somefile -r somerate`.
|
||||
@ -144,27 +153,57 @@ def get_args(stream_spec, overwrite_output=False):
|
||||
|
||||
|
||||
@output_operator()
|
||||
def compile(stream_spec, cmd='ffmpeg', **kwargs):
|
||||
"""Build command-line for ffmpeg."""
|
||||
def compile(stream_spec, cmd='ffmpeg', overwrite_output=False):
|
||||
"""Build command-line for invoking ffmpeg.
|
||||
|
||||
The :meth:`run` function uses this to build the commnad line
|
||||
arguments and should work in most cases, but calling this function
|
||||
directly is useful for debugging or if you need to invoke ffmpeg
|
||||
manually for whatever reason.
|
||||
|
||||
This is the same as calling :meth:`get_args` except that it also
|
||||
includes the ``ffmpeg`` command as the first argument.
|
||||
"""
|
||||
if isinstance(cmd, basestring):
|
||||
cmd = [cmd]
|
||||
elif type(cmd) != list:
|
||||
cmd = list(cmd)
|
||||
return cmd + get_args(stream_spec, **kwargs)
|
||||
return cmd + get_args(stream_spec, overwrite_output=overwrite_output)
|
||||
|
||||
|
||||
@output_operator()
|
||||
def run(stream_spec, cmd='ffmpeg', **kwargs):
|
||||
"""Run ffmpeg on node graph.
|
||||
def run(
|
||||
stream_spec, cmd='ffmpeg', capture_stdout=False, capture_stderr=False, input=None,
|
||||
quiet=False, overwrite_output=False):
|
||||
"""Ivoke ffmpeg for the supplied node graph.
|
||||
|
||||
Args:
|
||||
**kwargs: keyword-arguments passed to ``get_args()`` (e.g. ``overwrite_output=True``).
|
||||
capture_stdout: if True, capture stdout (to be used with
|
||||
``pipe:`` ffmpeg outputs).
|
||||
capture_stderr: if True, capture stderr.
|
||||
quiet: shorthand for setting ``capture_stdout`` and ``capture_stderr``.
|
||||
input: text to be sent to stdin (to be used with ``pipe:``
|
||||
ffmpeg inputs)
|
||||
**kwargs: keyword-arguments passed to ``get_args()`` (e.g.
|
||||
``overwrite_output=True``).
|
||||
|
||||
Returns: (out, err) tuple containing captured stdout and stderr data.
|
||||
"""
|
||||
_subprocess.check_call(compile(stream_spec, cmd, **kwargs))
|
||||
args = compile(stream_spec, cmd, overwrite_output=overwrite_output)
|
||||
stdin_stream = subprocess.PIPE if input else None
|
||||
stdout_stream = subprocess.PIPE if capture_stdout or quiet else None
|
||||
stderr_stream = subprocess.PIPE if capture_stderr or quiet else None
|
||||
p = subprocess.Popen(args, stdin=stdin_stream, stdout=stdout_stream, stderr=stderr_stream)
|
||||
out, err = p.communicate(input)
|
||||
retcode = p.poll()
|
||||
if retcode:
|
||||
raise Error(stream_spec, out, err)
|
||||
return out, err
|
||||
|
||||
|
||||
__all__ = [
|
||||
'compile',
|
||||
'Error',
|
||||
'get_args',
|
||||
'run',
|
||||
]
|
||||
|
@ -111,6 +111,10 @@ def test_global_args():
|
||||
assert out_file.get_args() == ['-i', 'dummy.mp4', 'dummy2.mp4', '-progress', 'someurl']
|
||||
|
||||
|
||||
def _get_simple_example():
|
||||
return ffmpeg.input(TEST_INPUT_FILE1).output(TEST_OUTPUT_FILE1)
|
||||
|
||||
|
||||
def _get_complex_filter_example():
|
||||
split = (ffmpeg
|
||||
.input(TEST_INPUT_FILE1)
|
||||
@ -313,33 +317,72 @@ def test_compile():
|
||||
|
||||
def test_run():
|
||||
stream = _get_complex_filter_example()
|
||||
ffmpeg.run(stream)
|
||||
out, err = ffmpeg.run(stream)
|
||||
assert out is None
|
||||
assert err is None
|
||||
|
||||
|
||||
def test_run_multi_output():
|
||||
@pytest.mark.parametrize('capture_stdout', [True, False])
|
||||
@pytest.mark.parametrize('capture_stderr', [True, False])
|
||||
def test_run__capture_out(mocker, capture_stdout, capture_stderr):
|
||||
mocker.patch.object(ffmpeg._run, 'compile', return_value=['echo', 'test'])
|
||||
stream = _get_simple_example()
|
||||
out, err = ffmpeg.run(stream, capture_stdout=capture_stdout, capture_stderr=capture_stderr)
|
||||
if capture_stdout:
|
||||
assert out == 'test\n'
|
||||
else:
|
||||
assert out is None
|
||||
if capture_stderr:
|
||||
assert err == ''
|
||||
else:
|
||||
assert err is None
|
||||
|
||||
|
||||
def test_run__input_output(mocker):
|
||||
mocker.patch.object(ffmpeg._run, 'compile', return_value=['cat'])
|
||||
stream = _get_simple_example()
|
||||
out, err = ffmpeg.run(stream, input='test', capture_stdout=True)
|
||||
assert out == 'test'
|
||||
assert err is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize('capture_stdout', [True, False])
|
||||
@pytest.mark.parametrize('capture_stderr', [True, False])
|
||||
def test_run__error(mocker, capture_stdout, capture_stderr):
|
||||
mocker.patch.object(ffmpeg._run, 'compile', return_value=['ffmpeg'])
|
||||
stream = _get_complex_filter_example()
|
||||
with pytest.raises(ffmpeg.Error) as excinfo:
|
||||
out, err = ffmpeg.run(stream, capture_stdout=capture_stdout, capture_stderr=capture_stderr)
|
||||
out = excinfo.value.stdout
|
||||
err = excinfo.value.stderr
|
||||
if capture_stdout:
|
||||
assert out == ''
|
||||
else:
|
||||
assert out is None
|
||||
if capture_stderr:
|
||||
assert err.startswith('ffmpeg version')
|
||||
else:
|
||||
assert err is None
|
||||
|
||||
|
||||
def test_run__multi_output():
|
||||
in_ = ffmpeg.input(TEST_INPUT_FILE1)
|
||||
out1 = in_.output(TEST_OUTPUT_FILE1)
|
||||
out2 = in_.output(TEST_OUTPUT_FILE2)
|
||||
ffmpeg.run([out1, out2], overwrite_output=True)
|
||||
|
||||
|
||||
def test_run_dummy_cmd():
|
||||
def test_run__dummy_cmd():
|
||||
stream = _get_complex_filter_example()
|
||||
ffmpeg.run(stream, cmd='true')
|
||||
|
||||
|
||||
def test_run_dummy_cmd_list():
|
||||
def test_run__dummy_cmd_list():
|
||||
stream = _get_complex_filter_example()
|
||||
ffmpeg.run(stream, cmd=['true', 'ignored'])
|
||||
|
||||
|
||||
def test_run_failing_cmd():
|
||||
stream = _get_complex_filter_example()
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
ffmpeg.run(stream, cmd='false')
|
||||
|
||||
|
||||
def test_custom_filter():
|
||||
def test_filter__custom():
|
||||
stream = ffmpeg.input('dummy.mp4')
|
||||
stream = ffmpeg.filter_(stream, 'custom_filter', 'a', 'b', kwarg1='c')
|
||||
stream = ffmpeg.output(stream, 'dummy2.mp4')
|
||||
@ -351,7 +394,7 @@ def test_custom_filter():
|
||||
]
|
||||
|
||||
|
||||
def test_custom_filter_fluent():
|
||||
def test_filter__custom_fluent():
|
||||
stream = (ffmpeg
|
||||
.input('dummy.mp4')
|
||||
.filter_('custom_filter', 'a', 'b', kwarg1='c')
|
||||
|
@ -1,5 +1,6 @@
|
||||
future
|
||||
pytest
|
||||
pytest-mock
|
||||
pytest-runner
|
||||
sphinx
|
||||
tox
|
||||
|
@ -1,18 +1,26 @@
|
||||
alabaster==0.7.10
|
||||
apipkg==1.4
|
||||
Babel==2.5.1
|
||||
certifi==2017.7.27.1
|
||||
chardet==3.0.4
|
||||
docutils==0.14
|
||||
execnet==1.5.0
|
||||
funcsigs==1.0.2
|
||||
future==0.16.0
|
||||
idna==2.6
|
||||
imagesize==0.7.1
|
||||
Jinja2==2.9.6
|
||||
MarkupSafe==1.0
|
||||
mock==2.0.0
|
||||
pbr==4.0.3
|
||||
pluggy==0.5.2
|
||||
py==1.4.34
|
||||
Pygments==2.2.0
|
||||
pytest==3.2.3
|
||||
pytest-forked==0.2
|
||||
pytest-mock==1.10.0
|
||||
pytest-runner==3.0
|
||||
pytest-xdist==1.22.2
|
||||
pytz==2017.3
|
||||
requests==2.18.4
|
||||
six==1.11.0
|
||||
|
2
setup.py
2
setup.py
@ -57,7 +57,7 @@ setup(
|
||||
name='ffmpeg-python',
|
||||
packages=['ffmpeg'],
|
||||
setup_requires=['pytest-runner'],
|
||||
tests_require=['pytest'],
|
||||
tests_require=['pytest', 'pytest-mock'],
|
||||
version=version,
|
||||
description='Python bindings for FFmpeg - with support for complex filtering',
|
||||
author='Karl Kroening',
|
||||
|
Loading…
x
Reference in New Issue
Block a user