mirror of
https://github.com/kkroening/ffmpeg-python.git
synced 2025-08-10 21:20:08 +08:00
Re-apply Black formatting, and wrap docstrings at ~88 columns.
This commit is contained in:
parent
f3079726fa
commit
2cafbba33c
@ -34,8 +34,7 @@ def input(filename, **kwargs):
|
|||||||
|
|
||||||
@output_operator()
|
@output_operator()
|
||||||
def global_args(stream, *args):
|
def global_args(stream, *args):
|
||||||
"""Add extra global command-line argument(s), e.g. ``-progress``.
|
"""Add extra global command-line argument(s), e.g. ``-progress``."""
|
||||||
"""
|
|
||||||
return GlobalNode(stream, global_args.__name__, args).stream()
|
return GlobalNode(stream, global_args.__name__, args).stream()
|
||||||
|
|
||||||
|
|
||||||
@ -50,8 +49,7 @@ def overwrite_output(stream):
|
|||||||
|
|
||||||
@output_operator()
|
@output_operator()
|
||||||
def merge_outputs(*streams):
|
def merge_outputs(*streams):
|
||||||
"""Include all given outputs in one ffmpeg command line
|
"""Include all given outputs in one ffmpeg command line"""
|
||||||
"""
|
|
||||||
return MergeOutputsNode(streams, merge_outputs.__name__).stream()
|
return MergeOutputsNode(streams, merge_outputs.__name__).stream()
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,9 +8,11 @@ from ._utils import escape_chars
|
|||||||
def filter_multi_output(stream_spec, filter_name, *args, **kwargs):
|
def filter_multi_output(stream_spec, filter_name, *args, **kwargs):
|
||||||
"""Apply custom filter with one or more outputs.
|
"""Apply custom filter with one or more outputs.
|
||||||
|
|
||||||
This is the same as ``filter`` except that the filter can produce more than one output.
|
This is the same as ``filter`` except that the filter can produce more than one
|
||||||
|
output.
|
||||||
|
|
||||||
To reference an output stream, use either the ``.stream`` operator or bracket shorthand:
|
To reference an output stream, use either the ``.stream`` operator or bracket
|
||||||
|
shorthand:
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -30,9 +32,10 @@ def filter_multi_output(stream_spec, filter_name, *args, **kwargs):
|
|||||||
def filter(stream_spec, filter_name, *args, **kwargs):
|
def filter(stream_spec, filter_name, *args, **kwargs):
|
||||||
"""Apply custom filter.
|
"""Apply custom filter.
|
||||||
|
|
||||||
``filter_`` is normally used by higher-level filter functions such as ``hflip``, but if a filter implementation
|
``filter_`` is normally used by higher-level filter functions such as ``hflip``,
|
||||||
is missing from ``ffmpeg-python``, you can call ``filter_`` directly to have ``ffmpeg-python`` pass the filter name
|
but if a filter implementation is missing from ``ffmpeg-python``, you can call
|
||||||
and arguments to ffmpeg verbatim.
|
``filter_`` directly to have ``ffmpeg-python`` pass the filter name and arguments
|
||||||
|
to ffmpeg verbatim.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
stream_spec: a Stream, list of Streams, or label-to-Stream dictionary mapping
|
stream_spec: a Stream, list of Streams, or label-to-Stream dictionary mapping
|
||||||
@ -40,7 +43,8 @@ def filter(stream_spec, filter_name, *args, **kwargs):
|
|||||||
*args: list of args to pass to ffmpeg verbatim
|
*args: list of args to pass to ffmpeg verbatim
|
||||||
**kwargs: list of keyword-args to pass to ffmpeg verbatim
|
**kwargs: list of keyword-args to pass to ffmpeg verbatim
|
||||||
|
|
||||||
The function name is suffixed with ``_`` in order avoid confusion with the standard python ``filter`` function.
|
The function name is suffixed with ``_`` in order avoid confusion with the standard
|
||||||
|
python ``filter`` function.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -72,7 +76,8 @@ def setpts(stream, expr):
|
|||||||
"""Change the PTS (presentation timestamp) of the input frames.
|
"""Change the PTS (presentation timestamp) of the input frames.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
expr: The expression which is evaluated for each frame to construct its timestamp.
|
expr: The expression which is evaluated for each frame to construct its
|
||||||
|
timestamp.
|
||||||
|
|
||||||
Official documentation: `setpts, asetpts <https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts>`__
|
Official documentation: `setpts, asetpts <https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts>`__
|
||||||
"""
|
"""
|
||||||
@ -84,14 +89,15 @@ def trim(stream, **kwargs):
|
|||||||
"""Trim the input so that the output contains one continuous subpart of the input.
|
"""Trim the input so that the output contains one continuous subpart of the input.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
start: Specify the time of the start of the kept section, i.e. the frame with the timestamp start will be the
|
start: Specify the time of the start of the kept section, i.e. the frame with
|
||||||
first frame in the output.
|
the timestamp start will be the first frame in the output.
|
||||||
end: Specify the time of the first frame that will be dropped, i.e. the frame immediately preceding the one
|
end: Specify the time of the first frame that will be dropped, i.e. the frame
|
||||||
with the timestamp end will be the last frame in the output.
|
immediately preceding the one with the timestamp end will be the last frame
|
||||||
start_pts: This is the same as start, except this option sets the start timestamp in timebase units instead of
|
in the output.
|
||||||
seconds.
|
start_pts: This is the same as start, except this option sets the start
|
||||||
end_pts: This is the same as end, except this option sets the end timestamp in timebase units instead of
|
timestamp in timebase units instead of seconds.
|
||||||
seconds.
|
end_pts: This is the same as end, except this option sets the end timestamp in
|
||||||
|
timebase units instead of seconds.
|
||||||
duration: The maximum duration of the output in seconds.
|
duration: The maximum duration of the output in seconds.
|
||||||
start_frame: The number of the first frame that should be passed to the output.
|
start_frame: The number of the first frame that should be passed to the output.
|
||||||
end_frame: The number of the first frame that should be dropped.
|
end_frame: The number of the first frame that should be dropped.
|
||||||
@ -106,14 +112,16 @@ def overlay(main_parent_node, overlay_parent_node, eof_action='repeat', **kwargs
|
|||||||
"""Overlay one video on top of another.
|
"""Overlay one video on top of another.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
x: Set the expression for the x coordinates of the overlaid video on the main video. Default value is 0. In
|
x: Set the expression for the x coordinates of the overlaid video on the main
|
||||||
case the expression is invalid, it is set to a huge value (meaning that the overlay will not be displayed
|
video. Default value is 0. In case the expression is invalid, it is set to
|
||||||
within the output visible area).
|
a huge value (meaning that the overlay will not be displayed within the
|
||||||
y: Set the expression for the y coordinates of the overlaid video on the main video. Default value is 0. In
|
output visible area).
|
||||||
case the expression is invalid, it is set to a huge value (meaning that the overlay will not be displayed
|
y: Set the expression for the y coordinates of the overlaid video on the main
|
||||||
within the output visible area).
|
video. Default value is 0. In case the expression is invalid, it is set to
|
||||||
eof_action: The action to take when EOF is encountered on the secondary input; it accepts one of the following
|
a huge value (meaning that the overlay will not be displayed within the
|
||||||
values:
|
output visible area).
|
||||||
|
eof_action: The action to take when EOF is encountered on the secondary input;
|
||||||
|
it accepts one of the following values:
|
||||||
|
|
||||||
* ``repeat``: Repeat the last frame (the default).
|
* ``repeat``: Repeat the last frame (the default).
|
||||||
* ``endall``: End both streams.
|
* ``endall``: End both streams.
|
||||||
@ -122,12 +130,13 @@ def overlay(main_parent_node, overlay_parent_node, eof_action='repeat', **kwargs
|
|||||||
eval: Set when the expressions for x, and y are evaluated.
|
eval: Set when the expressions for x, and y are evaluated.
|
||||||
It accepts the following values:
|
It accepts the following values:
|
||||||
|
|
||||||
* ``init``: only evaluate expressions once during the filter initialization or when a command is
|
* ``init``: only evaluate expressions once during the filter initialization
|
||||||
processed
|
or when a command is processed
|
||||||
* ``frame``: evaluate expressions for each incoming frame
|
* ``frame``: evaluate expressions for each incoming frame
|
||||||
|
|
||||||
Default value is ``frame``.
|
Default value is ``frame``.
|
||||||
shortest: If set to 1, force the output to terminate when the shortest input terminates. Default value is 0.
|
shortest: If set to 1, force the output to terminate when the shortest input
|
||||||
|
terminates. Default value is 0.
|
||||||
format: Set the format for the output video.
|
format: Set the format for the output video.
|
||||||
It accepts the following values:
|
It accepts the following values:
|
||||||
|
|
||||||
@ -138,10 +147,12 @@ def overlay(main_parent_node, overlay_parent_node, eof_action='repeat', **kwargs
|
|||||||
* ``gbrp``: force planar RGB output
|
* ``gbrp``: force planar RGB output
|
||||||
|
|
||||||
Default value is ``yuv420``.
|
Default value is ``yuv420``.
|
||||||
rgb (deprecated): If set to 1, force the filter to accept inputs in the RGB color space. Default value is 0.
|
rgb (deprecated): If set to 1, force the filter to accept inputs in the RGB
|
||||||
This option is deprecated, use format instead.
|
color space. Default value is 0. This option is deprecated, use format
|
||||||
repeatlast: If set to 1, force the filter to draw the last overlay frame over the main input until the end of
|
instead.
|
||||||
the stream. A value of 0 disables this behavior. Default value is 1.
|
repeatlast: If set to 1, force the filter to draw the last overlay frame over
|
||||||
|
the main input until the end of the stream. A value of 0 disables this
|
||||||
|
behavior. Default value is 1.
|
||||||
|
|
||||||
Official documentation: `overlay <https://ffmpeg.org/ffmpeg-filters.html#overlay-1>`__
|
Official documentation: `overlay <https://ffmpeg.org/ffmpeg-filters.html#overlay-1>`__
|
||||||
"""
|
"""
|
||||||
@ -196,14 +207,20 @@ def drawbox(stream, x, y, width, height, color, thickness=None, **kwargs):
|
|||||||
"""Draw a colored box on the input image.
|
"""Draw a colored box on the input image.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
x: The expression which specifies the top left corner x coordinate of the box. It defaults to 0.
|
x: The expression which specifies the top left corner x coordinate of the box.
|
||||||
y: The expression which specifies the top left corner y coordinate of the box. It defaults to 0.
|
It defaults to 0.
|
||||||
width: Specify the width of the box; if 0 interpreted as the input width. It defaults to 0.
|
y: The expression which specifies the top left corner y coordinate of the box.
|
||||||
heigth: Specify the height of the box; if 0 interpreted as the input height. It defaults to 0.
|
It defaults to 0.
|
||||||
color: Specify the color of the box to write. For the general syntax of this option, check the "Color" section
|
width: Specify the width of the box; if 0 interpreted as the input width. It
|
||||||
in the ffmpeg-utils manual. If the special value invert is used, the box edge color is the same as the
|
defaults to 0.
|
||||||
video with inverted luma.
|
heigth: Specify the height of the box; if 0 interpreted as the input height. It
|
||||||
thickness: The expression which sets the thickness of the box edge. Default value is 3.
|
defaults to 0.
|
||||||
|
color: Specify the color of the box to write. For the general syntax of this
|
||||||
|
option, check the "Color" section in the ffmpeg-utils manual. If the
|
||||||
|
special value invert is used, the box edge color is the same as the video
|
||||||
|
with inverted luma.
|
||||||
|
thickness: The expression which sets the thickness of the box edge. Default
|
||||||
|
value is 3.
|
||||||
w: Alias for ``width``.
|
w: Alias for ``width``.
|
||||||
h: Alias for ``height``.
|
h: Alias for ``height``.
|
||||||
c: Alias for ``color``.
|
c: Alias for ``color``.
|
||||||
@ -220,46 +237,57 @@ def drawbox(stream, x, y, width, height, color, thickness=None, **kwargs):
|
|||||||
|
|
||||||
@filter_operator()
|
@filter_operator()
|
||||||
def drawtext(stream, text=None, x=0, y=0, escape_text=True, **kwargs):
|
def drawtext(stream, text=None, x=0, y=0, escape_text=True, **kwargs):
|
||||||
"""Draw a text string or text from a specified file on top of a video, using the libfreetype library.
|
"""Draw a text string or text from a specified file on top of a video, using the
|
||||||
|
libfreetype library.
|
||||||
|
|
||||||
To enable compilation of this filter, you need to configure FFmpeg with ``--enable-libfreetype``. To enable default
|
To enable compilation of this filter, you need to configure FFmpeg with
|
||||||
font fallback and the font option you need to configure FFmpeg with ``--enable-libfontconfig``. To enable the
|
``--enable-libfreetype``. To enable default font fallback and the font option you
|
||||||
|
need to configure FFmpeg with ``--enable-libfontconfig``. To enable the
|
||||||
text_shaping option, you need to configure FFmpeg with ``--enable-libfribidi``.
|
text_shaping option, you need to configure FFmpeg with ``--enable-libfribidi``.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
box: Used to draw a box around text using the background color. The value must be either 1 (enable) or 0
|
box: Used to draw a box around text using the background color. The value must
|
||||||
(disable). The default value of box is 0.
|
be either 1 (enable) or 0 (disable). The default value of box is 0.
|
||||||
boxborderw: Set the width of the border to be drawn around the box using boxcolor. The default value of
|
boxborderw: Set the width of the border to be drawn around the box using
|
||||||
boxborderw is 0.
|
boxcolor. The default value of boxborderw is 0.
|
||||||
boxcolor: The color to be used for drawing box around text. For the syntax of this option, check the "Color"
|
boxcolor: The color to be used for drawing box around text. For the syntax of
|
||||||
section in the ffmpeg-utils manual. The default value of boxcolor is "white".
|
this option, check the "Color" section in the ffmpeg-utils manual. The
|
||||||
line_spacing: Set the line spacing in pixels of the border to be drawn around the box using box. The default
|
default value of boxcolor is "white".
|
||||||
value of line_spacing is 0.
|
line_spacing: Set the line spacing in pixels of the border to be drawn around
|
||||||
borderw: Set the width of the border to be drawn around the text using bordercolor. The default value of
|
the box using box. The default value of line_spacing is 0.
|
||||||
borderw is 0.
|
borderw: Set the width of the border to be drawn around the text using
|
||||||
bordercolor: Set the color to be used for drawing border around text. For the syntax of this option, check the
|
bordercolor. The default value of borderw is 0.
|
||||||
"Color" section in the ffmpeg-utils manual. The default value of bordercolor is "black".
|
bordercolor: Set the color to be used for drawing border around text. For the
|
||||||
expansion: Select how the text is expanded. Can be either none, strftime (deprecated) or normal (default). See
|
syntax of this option, check the "Color" section in the ffmpeg-utils
|
||||||
the Text expansion section below for details.
|
manual. The default value of bordercolor is "black".
|
||||||
basetime: Set a start time for the count. Value is in microseconds. Only applied in the deprecated strftime
|
expansion: Select how the text is expanded. Can be either none, strftime
|
||||||
expansion mode. To emulate in normal expansion mode use the pts function, supplying the start time (in
|
(deprecated) or normal (default). See the Text expansion section below for
|
||||||
seconds) as the second argument.
|
details.
|
||||||
|
basetime: Set a start time for the count. Value is in microseconds. Only
|
||||||
|
applied in the deprecated strftime expansion mode. To emulate in normal
|
||||||
|
expansion mode use the pts function, supplying the start time (in seconds)
|
||||||
|
as the second argument.
|
||||||
fix_bounds: If true, check and fix text coords to avoid clipping.
|
fix_bounds: If true, check and fix text coords to avoid clipping.
|
||||||
fontcolor: The color to be used for drawing fonts. For the syntax of this option, check the "Color" section in
|
fontcolor: The color to be used for drawing fonts. For the syntax of this
|
||||||
the ffmpeg-utils manual. The default value of fontcolor is "black".
|
option, check the "Color" section in the ffmpeg-utils manual. The default
|
||||||
fontcolor_expr: String which is expanded the same way as text to obtain dynamic fontcolor value. By default
|
value of fontcolor is "black".
|
||||||
this option has empty value and is not processed. When this option is set, it overrides fontcolor option.
|
fontcolor_expr: String which is expanded the same way as text to obtain dynamic
|
||||||
|
fontcolor value. By default this option has empty value and is not
|
||||||
|
processed. When this option is set, it overrides fontcolor option.
|
||||||
font: The font family to be used for drawing text. By default Sans.
|
font: The font family to be used for drawing text. By default Sans.
|
||||||
fontfile: The font file to be used for drawing text. The path must be included. This parameter is mandatory if
|
fontfile: The font file to be used for drawing text. The path must be included.
|
||||||
the fontconfig support is disabled.
|
This parameter is mandatory if the fontconfig support is disabled.
|
||||||
alpha: Draw the text applying alpha blending. The value can be a number between 0.0 and 1.0. The expression
|
alpha: Draw the text applying alpha blending. The value can be a number between
|
||||||
accepts the same variables x, y as well. The default value is 1. Please see fontcolor_expr.
|
0.0 and 1.0. The expression accepts the same variables x, y as well. The
|
||||||
fontsize: The font size to be used for drawing text. The default value of fontsize is 16.
|
default value is 1. Please see fontcolor_expr.
|
||||||
text_shaping: If set to 1, attempt to shape the text (for example, reverse the order of right-to-left text and
|
fontsize: The font size to be used for drawing text. The default value of
|
||||||
join Arabic characters) before drawing it. Otherwise, just draw the text exactly as given. By default 1 (if
|
fontsize is 16.
|
||||||
supported).
|
text_shaping: If set to 1, attempt to shape the text (for example, reverse the
|
||||||
ft_load_flags: The flags to be used for loading the fonts. The flags map the corresponding flags supported by
|
order of right-to-left text and join Arabic characters) before drawing it.
|
||||||
libfreetype, and are a combination of the following values:
|
Otherwise, just draw the text exactly as given. By default 1 (if supported).
|
||||||
|
ft_load_flags: The flags to be used for loading the fonts. The flags map the
|
||||||
|
corresponding flags supported by libfreetype, and are a combination of the
|
||||||
|
following values:
|
||||||
|
|
||||||
* ``default``
|
* ``default``
|
||||||
* ``no_scale``
|
* ``no_scale``
|
||||||
@ -277,75 +305,89 @@ def drawtext(stream, text=None, x=0, y=0, escape_text=True, **kwargs):
|
|||||||
* ``linear_design``
|
* ``linear_design``
|
||||||
* ``no_autohint``
|
* ``no_autohint``
|
||||||
|
|
||||||
Default value is "default". For more information consult the documentation for the FT_LOAD_* libfreetype
|
Default value is "default". For more information consult the documentation
|
||||||
flags.
|
for the FT_LOAD_* libfreetype flags.
|
||||||
shadowcolor: The color to be used for drawing a shadow behind the drawn text. For the syntax of this option,
|
shadowcolor: The color to be used for drawing a shadow behind the drawn text.
|
||||||
check the "Color" section in the ffmpeg-utils manual. The default value of shadowcolor is "black".
|
For the syntax of this option, check the "Color" section in the ffmpeg-utils
|
||||||
shadowx: The x offset for the text shadow position with respect to the position of the text. It can be either
|
manual. The default value of shadowcolor is "black".
|
||||||
positive or negative values. The default value is "0".
|
shadowx: The x offset for the text shadow position with respect to the position
|
||||||
shadowy: The y offset for the text shadow position with respect to the position of the text. It can be either
|
of the text. It can be either positive or negative values. The default value
|
||||||
positive or negative values. The default value is "0".
|
is "0".
|
||||||
start_number: The starting frame number for the n/frame_num variable. The default value is "0".
|
shadowy: The y offset for the text shadow position with respect to the position
|
||||||
tabsize: The size in number of spaces to use for rendering the tab. Default value is 4.
|
of the text. It can be either positive or negative values. The default value
|
||||||
timecode: Set the initial timecode representation in "hh:mm:ss[:;.]ff" format. It can be used with or without
|
is "0".
|
||||||
text parameter. timecode_rate option must be specified.
|
start_number: The starting frame number for the n/frame_num variable. The
|
||||||
|
default value is "0".
|
||||||
|
tabsize: The size in number of spaces to use for rendering the tab. Default
|
||||||
|
value is 4.
|
||||||
|
timecode: Set the initial timecode representation in "hh:mm:ss[:;.]ff" format.
|
||||||
|
It can be used with or without text parameter. timecode_rate option must be
|
||||||
|
specified.
|
||||||
rate: Set the timecode frame rate (timecode only).
|
rate: Set the timecode frame rate (timecode only).
|
||||||
timecode_rate: Alias for ``rate``.
|
timecode_rate: Alias for ``rate``.
|
||||||
r: Alias for ``rate``.
|
r: Alias for ``rate``.
|
||||||
tc24hmax: If set to 1, the output of the timecode option will wrap around at 24 hours. Default is 0 (disabled).
|
tc24hmax: If set to 1, the output of the timecode option will wrap around at 24
|
||||||
text: The text string to be drawn. The text must be a sequence of UTF-8 encoded characters. This parameter is
|
hours. Default is 0 (disabled).
|
||||||
mandatory if no file is specified with the parameter textfile.
|
text: The text string to be drawn. The text must be a sequence of UTF-8 encoded
|
||||||
textfile: A text file containing text to be drawn. The text must be a sequence of UTF-8 encoded characters.
|
characters. This parameter is mandatory if no file is specified with the
|
||||||
This parameter is mandatory if no text string is specified with the parameter text. If both text and
|
parameter textfile.
|
||||||
textfile are specified, an error is thrown.
|
textfile: A text file containing text to be drawn. The text must be a sequence
|
||||||
reload: If set to 1, the textfile will be reloaded before each frame. Be sure to update it atomically, or it
|
of UTF-8 encoded characters. This parameter is mandatory if no text string
|
||||||
may be read partially, or even fail.
|
is specified with the parameter text. If both text and textfile are
|
||||||
x: The expression which specifies the offset where text will be drawn within the video frame. It is relative to
|
specified, an error is thrown.
|
||||||
the left border of the output image. The default value is "0".
|
reload: If set to 1, the textfile will be reloaded before each frame. Be sure
|
||||||
y: The expression which specifies the offset where text will be drawn within the video frame. It is relative to
|
to update it atomically, or it may be read partially, or even fail.
|
||||||
the top border of the output image. The default value is "0". See below for the list of accepted constants
|
x: The expression which specifies the offset where text will be drawn within
|
||||||
and functions.
|
the video frame. It is relative to the left border of the output image. The
|
||||||
|
default value is "0".
|
||||||
|
y: The expression which specifies the offset where text will be drawn within
|
||||||
|
the video frame. It is relative to the top border of the output image. The
|
||||||
|
default value is "0". See below for the list of accepted constants and
|
||||||
|
functions.
|
||||||
|
|
||||||
Expression constants:
|
Expression constants:
|
||||||
The parameters for x and y are expressions containing the following constants and functions:
|
The parameters for x and y are expressions containing the following constants
|
||||||
- dar: input display aspect ratio, it is the same as ``(w / h) * sar``
|
and functions:
|
||||||
- hsub: horizontal chroma subsample values. For example for the pixel format "yuv422p" hsub is 2 and vsub
|
- dar: input display aspect ratio, it is the same as ``(w / h) * sar``
|
||||||
is 1.
|
- hsub: horizontal chroma subsample values. For example for the pixel format
|
||||||
- vsub: vertical chroma subsample values. For example for the pixel format "yuv422p" hsub is 2 and vsub
|
"yuv422p" hsub is 2 and vsub is 1.
|
||||||
is 1.
|
- vsub: vertical chroma subsample values. For example for the pixel format
|
||||||
- line_h: the height of each text line
|
"yuv422p" hsub is 2 and vsub is 1.
|
||||||
- lh: Alias for ``line_h``.
|
- line_h: the height of each text line
|
||||||
- main_h: the input height
|
- lh: Alias for ``line_h``.
|
||||||
- h: Alias for ``main_h``.
|
- main_h: the input height
|
||||||
- H: Alias for ``main_h``.
|
- h: Alias for ``main_h``.
|
||||||
- main_w: the input width
|
- H: Alias for ``main_h``.
|
||||||
- w: Alias for ``main_w``.
|
- main_w: the input width
|
||||||
- W: Alias for ``main_w``.
|
- w: Alias for ``main_w``.
|
||||||
- ascent: the maximum distance from the baseline to the highest/upper grid coordinate used to place a glyph
|
- W: Alias for ``main_w``.
|
||||||
outline point, for all the rendered glyphs. It is a positive value, due to the grid's orientation with the Y
|
- ascent: the maximum distance from the baseline to the highest/upper grid
|
||||||
axis upwards.
|
coordinate used to place a glyph outline point, for all the rendered glyphs.
|
||||||
- max_glyph_a: Alias for ``ascent``.
|
It is a positive value, due to the grid's orientation with the Y axis
|
||||||
- descent: the maximum distance from the baseline to the lowest grid coordinate used to place a glyph outline
|
upwards.
|
||||||
point, for all the rendered glyphs. This is a negative value, due to the grid's orientation, with the Y axis
|
- max_glyph_a: Alias for ``ascent``.
|
||||||
upwards.
|
- descent: the maximum distance from the baseline to the lowest grid
|
||||||
- max_glyph_d: Alias for ``descent``.
|
coordinate used to place a glyph outline
|
||||||
- max_glyph_h: maximum glyph height, that is the maximum height for all the glyphs contained in the rendered
|
point, for all the rendered glyphs. This is a negative value, due to the
|
||||||
text, it is equivalent to ascent - descent.
|
grid's orientation, with the Y axis upwards.
|
||||||
- max_glyph_w: maximum glyph width, that is the maximum width for all the glyphs contained in the rendered
|
- max_glyph_d: Alias for ``descent``.
|
||||||
text.
|
- max_glyph_h: maximum glyph height, that is the maximum height for all the
|
||||||
- n: the number of input frame, starting from 0
|
glyphs contained in the rendered text, it is equivalent to ascent - descent.
|
||||||
- rand(min, max): return a random number included between min and max
|
- max_glyph_w: maximum glyph width, that is the maximum width for all the
|
||||||
- sar: The input sample aspect ratio.
|
glyphs contained in the rendered text.
|
||||||
- t: timestamp expressed in seconds, NAN if the input timestamp is unknown
|
- n: the number of input frame, starting from 0
|
||||||
- text_h: the height of the rendered text
|
- rand(min, max): return a random number included between min and max
|
||||||
- th: Alias for ``text_h``.
|
- sar: The input sample aspect ratio.
|
||||||
- text_w: the width of the rendered text
|
- t: timestamp expressed in seconds, NAN if the input timestamp is unknown
|
||||||
- tw: Alias for ``text_w``.
|
- text_h: the height of the rendered text
|
||||||
- x: the x offset coordinates where the text is drawn.
|
- th: Alias for ``text_h``.
|
||||||
- y: the y offset coordinates where the text is drawn.
|
- text_w: the width of the rendered text
|
||||||
|
- tw: Alias for ``text_w``.
|
||||||
|
- x: the x offset coordinates where the text is drawn.
|
||||||
|
- y: the y offset coordinates where the text is drawn.
|
||||||
|
|
||||||
These parameters allow the x and y expressions to refer each other, so you can for example specify
|
These parameters allow the x and y expressions to refer each other, so you can
|
||||||
``y=x/dar``.
|
for example specify ``y=x/dar``.
|
||||||
|
|
||||||
Official documentation: `drawtext <https://ffmpeg.org/ffmpeg-filters.html#drawtext>`__
|
Official documentation: `drawtext <https://ffmpeg.org/ffmpeg-filters.html#drawtext>`__
|
||||||
"""
|
"""
|
||||||
@ -364,25 +406,28 @@ def drawtext(stream, text=None, x=0, y=0, escape_text=True, **kwargs):
|
|||||||
def concat(*streams, **kwargs):
|
def concat(*streams, **kwargs):
|
||||||
"""Concatenate audio and video streams, joining them together one after the other.
|
"""Concatenate audio and video streams, joining them together one after the other.
|
||||||
|
|
||||||
The filter works on segments of synchronized video and audio streams. All segments must have the same number of
|
The filter works on segments of synchronized video and audio streams. All segments
|
||||||
streams of each type, and that will also be the number of streams at output.
|
must have the same number of streams of each type, and that will also be the number
|
||||||
|
of streams at output.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
unsafe: Activate unsafe mode: do not fail if segments have a different format.
|
unsafe: Activate unsafe mode: do not fail if segments have a different format.
|
||||||
|
|
||||||
Related streams do not always have exactly the same duration, for various reasons including codec frame size or
|
Related streams do not always have exactly the same duration, for various reasons
|
||||||
sloppy authoring. For that reason, related synchronized streams (e.g. a video and its audio track) should be
|
including codec frame size or sloppy authoring. For that reason, related
|
||||||
concatenated at once. The concat filter will use the duration of the longest stream in each segment (except the
|
synchronized streams (e.g. a video and its audio track) should be concatenated at
|
||||||
last one), and if necessary pad shorter audio streams with silence.
|
once. The concat filter will use the duration of the longest stream in each segment
|
||||||
|
(except the last one), and if necessary pad shorter audio streams with silence.
|
||||||
|
|
||||||
For this filter to work correctly, all segments must start at timestamp 0.
|
For this filter to work correctly, all segments must start at timestamp 0.
|
||||||
|
|
||||||
All corresponding streams must have the same parameters in all segments; the filtering system will automatically
|
All corresponding streams must have the same parameters in all segments; the
|
||||||
select a common pixel format for video streams, and a common sample format, sample rate and channel layout for
|
filtering system will automatically select a common pixel format for video streams,
|
||||||
audio streams, but other settings, such as resolution, must be converted explicitly by the user.
|
and a common sample format, sample rate and channel layout for audio streams, but
|
||||||
|
other settings, such as resolution, must be converted explicitly by the user.
|
||||||
|
|
||||||
Different frame rates are acceptable but will result in variable frame rate at output; be sure to configure the
|
Different frame rates are acceptable but will result in variable frame rate at
|
||||||
output file to handle it.
|
output; be sure to configure the output file to handle it.
|
||||||
|
|
||||||
Official documentation: `concat <https://ffmpeg.org/ffmpeg-filters.html#concat>`__
|
Official documentation: `concat <https://ffmpeg.org/ffmpeg-filters.html#concat>`__
|
||||||
"""
|
"""
|
||||||
@ -407,8 +452,8 @@ def zoompan(stream, **kwargs):
|
|||||||
zoom: Set the zoom expression. Default is 1.
|
zoom: Set the zoom expression. Default is 1.
|
||||||
x: Set the x expression. Default is 0.
|
x: Set the x expression. Default is 0.
|
||||||
y: Set the y expression. Default is 0.
|
y: Set the y expression. Default is 0.
|
||||||
d: Set the duration expression in number of frames. This sets for how many number of frames effect will last
|
d: Set the duration expression in number of frames. This sets for how many
|
||||||
for single input image.
|
number of frames effect will last for single input image.
|
||||||
s: Set the output image size, default is ``hd720``.
|
s: Set the output image size, default is ``hd720``.
|
||||||
fps: Set the output frame rate, default is 25.
|
fps: Set the output frame rate, default is 25.
|
||||||
z: Alias for ``zoom``.
|
z: Alias for ``zoom``.
|
||||||
@ -423,10 +468,14 @@ def hue(stream, **kwargs):
|
|||||||
"""Modify the hue and/or the saturation of the input.
|
"""Modify the hue and/or the saturation of the input.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
h: Specify the hue angle as a number of degrees. It accepts an expression, and defaults to "0".
|
h: Specify the hue angle as a number of degrees. It accepts an expression, and
|
||||||
s: Specify the saturation in the [-10,10] range. It accepts an expression and defaults to "1".
|
defaults to "0".
|
||||||
H: Specify the hue angle as a number of radians. It accepts an expression, and defaults to "0".
|
s: Specify the saturation in the [-10,10] range. It accepts an expression and
|
||||||
b: Specify the brightness in the [-10,10] range. It accepts an expression and defaults to "0".
|
defaults to "1".
|
||||||
|
H: Specify the hue angle as a number of radians. It accepts an expression, and
|
||||||
|
defaults to "0".
|
||||||
|
b: Specify the brightness in the [-10,10] range. It accepts an expression and
|
||||||
|
defaults to "0".
|
||||||
|
|
||||||
Official documentation: `hue <https://ffmpeg.org/ffmpeg-filters.html#hue>`__
|
Official documentation: `hue <https://ffmpeg.org/ffmpeg-filters.html#hue>`__
|
||||||
"""
|
"""
|
||||||
|
@ -88,8 +88,8 @@ def _allocate_filter_stream_names(filter_nodes, outgoing_edge_maps, stream_name_
|
|||||||
if len(downstreams) > 1:
|
if len(downstreams) > 1:
|
||||||
# TODO: automatically insert `splits` ahead of time via graph transformation.
|
# TODO: automatically insert `splits` ahead of time via graph transformation.
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'Encountered {} with multiple outgoing edges with same upstream label {!r}; a '
|
'Encountered {} with multiple outgoing edges with same upstream '
|
||||||
'`split` filter is probably required'.format(
|
'label {!r}; a `split` filter is probably required'.format(
|
||||||
upstream_node, upstream_label
|
upstream_node, upstream_label
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -199,7 +199,7 @@ def run_async(
|
|||||||
pipe_stderr=False,
|
pipe_stderr=False,
|
||||||
quiet=False,
|
quiet=False,
|
||||||
overwrite_output=False,
|
overwrite_output=False,
|
||||||
cwd=None
|
cwd=None,
|
||||||
):
|
):
|
||||||
"""Asynchronously invoke ffmpeg for the supplied node graph.
|
"""Asynchronously invoke ffmpeg for the supplied node graph.
|
||||||
|
|
||||||
@ -286,8 +286,11 @@ def run_async(
|
|||||||
stderr_stream = subprocess.STDOUT
|
stderr_stream = subprocess.STDOUT
|
||||||
stdout_stream = subprocess.DEVNULL
|
stdout_stream = subprocess.DEVNULL
|
||||||
return subprocess.Popen(
|
return subprocess.Popen(
|
||||||
args, stdin=stdin_stream, stdout=stdout_stream, stderr=stderr_stream,
|
args,
|
||||||
cwd=cwd
|
stdin=stdin_stream,
|
||||||
|
stdout=stdout_stream,
|
||||||
|
stderr=stderr_stream,
|
||||||
|
cwd=cwd,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -300,7 +303,7 @@ def run(
|
|||||||
input=None,
|
input=None,
|
||||||
quiet=False,
|
quiet=False,
|
||||||
overwrite_output=False,
|
overwrite_output=False,
|
||||||
cwd=None
|
cwd=None,
|
||||||
):
|
):
|
||||||
"""Invoke ffmpeg for the supplied node graph.
|
"""Invoke ffmpeg for the supplied node graph.
|
||||||
|
|
||||||
@ -324,7 +327,7 @@ def run(
|
|||||||
pipe_stderr=capture_stderr,
|
pipe_stderr=capture_stderr,
|
||||||
quiet=quiet,
|
quiet=quiet,
|
||||||
overwrite_output=overwrite_output,
|
overwrite_output=overwrite_output,
|
||||||
cwd=cwd
|
cwd=cwd,
|
||||||
)
|
)
|
||||||
out, err = process.communicate(input)
|
out, err = process.communicate(input)
|
||||||
retcode = process.poll()
|
retcode = process.poll()
|
||||||
@ -333,4 +336,10 @@ def run(
|
|||||||
return out, err
|
return out, err
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['compile', 'Error', 'get_args', 'run', 'run_async']
|
__all__ = [
|
||||||
|
'compile',
|
||||||
|
'Error',
|
||||||
|
'get_args',
|
||||||
|
'run',
|
||||||
|
'run_async',
|
||||||
|
]
|
||||||
|
@ -49,8 +49,8 @@ else:
|
|||||||
def _recursive_repr(item):
|
def _recursive_repr(item):
|
||||||
"""Hack around python `repr` to deterministically represent dictionaries.
|
"""Hack around python `repr` to deterministically represent dictionaries.
|
||||||
|
|
||||||
This is able to represent more things than json.dumps, since it does not require things to be JSON serializable
|
This is able to represent more things than json.dumps, since it does not require
|
||||||
(e.g. datetimes).
|
things to be JSON serializable (e.g. datetimes).
|
||||||
"""
|
"""
|
||||||
if isinstance(item, basestring):
|
if isinstance(item, basestring):
|
||||||
result = str(item)
|
result = str(item)
|
||||||
|
@ -35,8 +35,8 @@ def view(stream_spec, detail=False, filename=None, pipe=False, **kwargs):
|
|||||||
import graphviz
|
import graphviz
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise ImportError(
|
raise ImportError(
|
||||||
'failed to import graphviz; please make sure graphviz is installed (e.g. `pip install '
|
'failed to import graphviz; please make sure graphviz is installed (e.g. '
|
||||||
'graphviz`)'
|
'`pip install graphviz`)'
|
||||||
)
|
)
|
||||||
|
|
||||||
show_labels = kwargs.pop('show_labels', True)
|
show_labels = kwargs.pop('show_labels', True)
|
||||||
|
@ -9,38 +9,45 @@ class DagNode(object):
|
|||||||
"""Node in a directed-acyclic graph (DAG).
|
"""Node in a directed-acyclic graph (DAG).
|
||||||
|
|
||||||
Edges:
|
Edges:
|
||||||
DagNodes are connected by edges. An edge connects two nodes with a label for each side:
|
DagNodes are connected by edges. An edge connects two nodes with a label for
|
||||||
|
each side:
|
||||||
- ``upstream_node``: upstream/parent node
|
- ``upstream_node``: upstream/parent node
|
||||||
- ``upstream_label``: label on the outgoing side of the upstream node
|
- ``upstream_label``: label on the outgoing side of the upstream node
|
||||||
- ``downstream_node``: downstream/child node
|
- ``downstream_node``: downstream/child node
|
||||||
- ``downstream_label``: label on the incoming side of the downstream node
|
- ``downstream_label``: label on the incoming side of the downstream node
|
||||||
|
|
||||||
For example, DagNode A may be connected to DagNode B with an edge labelled "foo" on A's side, and "bar" on B's
|
For example, DagNode A may be connected to DagNode B with an edge labelled
|
||||||
side:
|
"foo" on A's side, and "bar" on B's side:
|
||||||
|
|
||||||
_____ _____
|
_____ _____
|
||||||
| | | |
|
| | | |
|
||||||
| A >[foo]---[bar]> B |
|
| A >[foo]---[bar]> B |
|
||||||
|_____| |_____|
|
|_____| |_____|
|
||||||
|
|
||||||
Edge labels may be integers or strings, and nodes cannot have more than one incoming edge with the same label.
|
Edge labels may be integers or strings, and nodes cannot have more than one
|
||||||
|
incoming edge with the same label.
|
||||||
|
|
||||||
DagNodes may have any number of incoming edges and any number of outgoing edges. DagNodes keep track only of
|
DagNodes may have any number of incoming edges and any number of outgoing
|
||||||
their incoming edges, but the entire graph structure can be inferred by looking at the furthest downstream
|
edges. DagNodes keep track only of their incoming edges, but the entire graph
|
||||||
nodes and working backwards.
|
structure can be inferred by looking at the furthest downstream nodes and
|
||||||
|
working backwards.
|
||||||
|
|
||||||
Hashing:
|
Hashing:
|
||||||
DagNodes must be hashable, and two nodes are considered to be equivalent if they have the same hash value.
|
DagNodes must be hashable, and two nodes are considered to be equivalent if
|
||||||
|
they have the same hash value.
|
||||||
|
|
||||||
Nodes are immutable, and the hash should remain constant as a result. If a node with new contents is required,
|
Nodes are immutable, and the hash should remain constant as a result. If a
|
||||||
create a new node and throw the old one away.
|
node with new contents is required, create a new node and throw the old one
|
||||||
|
away.
|
||||||
|
|
||||||
String representation:
|
String representation:
|
||||||
In order for graph visualization tools to show useful information, nodes must be representable as strings. The
|
In order for graph visualization tools to show useful information, nodes must
|
||||||
``repr`` operator should provide a more or less "full" representation of the node, and the ``short_repr``
|
be representable as strings. The ``repr`` operator should provide a more or
|
||||||
property should be a shortened, concise representation.
|
less "full" representation of the node, and the ``short_repr`` property should
|
||||||
|
be a shortened, concise representation.
|
||||||
|
|
||||||
Again, because nodes are immutable, the string representations should remain constant.
|
Again, because nodes are immutable, the string representations should remain
|
||||||
|
constant.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
@ -48,7 +55,9 @@ class DagNode(object):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"""Compare two nodes; implementations should return True if (and only if) hashes match."""
|
"""Compare two nodes; implementations should return True if (and only if)
|
||||||
|
hashes match.
|
||||||
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def __repr__(self, other):
|
def __repr__(self, other):
|
||||||
@ -64,8 +73,9 @@ class DagNode(object):
|
|||||||
def incoming_edge_map(self):
|
def incoming_edge_map(self):
|
||||||
"""Provides information about all incoming edges that connect to this node.
|
"""Provides information about all incoming edges that connect to this node.
|
||||||
|
|
||||||
The edge map is a dictionary that maps an ``incoming_label`` to ``(outgoing_node, outgoing_label)``. Note that
|
The edge map is a dictionary that maps an ``incoming_label`` to
|
||||||
implicity, ``incoming_node`` is ``self``. See "Edges" section above.
|
``(outgoing_node, outgoing_label)``. Note that implicity, ``incoming_node`` is
|
||||||
|
``self``. See "Edges" section above.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@ -116,8 +126,7 @@ def get_outgoing_edges(upstream_node, outgoing_edge_map):
|
|||||||
|
|
||||||
|
|
||||||
class KwargReprNode(DagNode):
|
class KwargReprNode(DagNode):
|
||||||
"""A DagNode that can be represented as a set of args+kwargs.
|
"""A DagNode that can be represented as a set of args+kwargs."""
|
||||||
"""
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def __upstream_hashes(self):
|
def __upstream_hashes(self):
|
||||||
|
@ -21,7 +21,9 @@ def _get_types_str(types):
|
|||||||
|
|
||||||
|
|
||||||
class Stream(object):
|
class Stream(object):
|
||||||
"""Represents the outgoing edge of an upstream node; may be used to create more downstream nodes."""
|
"""Represents the outgoing edge of an upstream node; may be used to create more
|
||||||
|
downstream nodes.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, upstream_node, upstream_label, node_types, upstream_selector=None
|
self, upstream_node, upstream_label, node_types, upstream_selector=None
|
||||||
@ -214,9 +216,10 @@ class Node(KwargReprNode):
|
|||||||
return self.__outgoing_stream_type(self, label, upstream_selector=selector)
|
return self.__outgoing_stream_type(self, label, upstream_selector=selector)
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
"""Create an outgoing stream originating from this node; syntactic sugar for ``self.stream(label)``.
|
"""Create an outgoing stream originating from this node; syntactic sugar for
|
||||||
It can also be used to apply a selector: e.g. ``node[0:'a']`` returns a stream with label 0 and
|
``self.stream(label)``. It can also be used to apply a selector: e.g.
|
||||||
selector ``'a'``, which is the same as ``node.stream(label=0, selector='a')``.
|
``node[0:'a']`` returns a stream with label 0 and selector ``'a'``, which is
|
||||||
|
the same as ``node.stream(label=0, selector='a')``.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Process the audio and video portions of a stream independently::
|
Process the audio and video portions of a stream independently::
|
||||||
|
@ -116,9 +116,20 @@ def test_stream_repr():
|
|||||||
dummy_out.label, dummy_out.node.short_hash
|
dummy_out.label, dummy_out.node.short_hash
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_repeated_args():
|
def test_repeated_args():
|
||||||
out_file = ffmpeg.input('dummy.mp4').output('dummy2.mp4', streamid=['0:0x101', '1:0x102'])
|
out_file = ffmpeg.input('dummy.mp4').output(
|
||||||
assert out_file.get_args() == ['-i', 'dummy.mp4', '-streamid', '0:0x101', '-streamid', '1:0x102', 'dummy2.mp4']
|
'dummy2.mp4', streamid=['0:0x101', '1:0x102']
|
||||||
|
)
|
||||||
|
assert out_file.get_args() == [
|
||||||
|
'-i',
|
||||||
|
'dummy.mp4',
|
||||||
|
'-streamid',
|
||||||
|
'0:0x101',
|
||||||
|
'-streamid',
|
||||||
|
'1:0x102',
|
||||||
|
'dummy2.mp4',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test__get_args__simple():
|
def test__get_args__simple():
|
||||||
@ -332,8 +343,13 @@ def test_filter_asplit():
|
|||||||
'-i',
|
'-i',
|
||||||
TEST_INPUT_FILE1,
|
TEST_INPUT_FILE1,
|
||||||
'-filter_complex',
|
'-filter_complex',
|
||||||
'[0]vflip[s0];[s0]asplit=2[s1][s2];[s1]atrim=end=20:start=10[s3];[s2]atrim=end=40:start=30[s4];[s3]'
|
(
|
||||||
'[s4]concat=n=2[s5]',
|
'[0]vflip[s0];'
|
||||||
|
'[s0]asplit=2[s1][s2];'
|
||||||
|
'[s1]atrim=end=20:start=10[s3];'
|
||||||
|
'[s2]atrim=end=40:start=30[s4];'
|
||||||
|
'[s3][s4]concat=n=2[s5]'
|
||||||
|
),
|
||||||
'-map',
|
'-map',
|
||||||
'[s5]',
|
'[s5]',
|
||||||
TEST_OUTPUT_FILE1,
|
TEST_OUTPUT_FILE1,
|
||||||
@ -357,10 +373,14 @@ def test__output__video_size(video_size):
|
|||||||
|
|
||||||
|
|
||||||
def test_filter_normal_arg_escape():
|
def test_filter_normal_arg_escape():
|
||||||
"""Test string escaping of normal filter args (e.g. ``font`` param of ``drawtext`` filter)."""
|
"""Test string escaping of normal filter args (e.g. ``font`` param of ``drawtext``
|
||||||
|
filter).
|
||||||
|
"""
|
||||||
|
|
||||||
def _get_drawtext_font_repr(font):
|
def _get_drawtext_font_repr(font):
|
||||||
"""Build a command-line arg using drawtext ``font`` param and extract the ``-filter_complex`` arg."""
|
"""Build a command-line arg using drawtext ``font`` param and extract the
|
||||||
|
``-filter_complex`` arg.
|
||||||
|
"""
|
||||||
args = (
|
args = (
|
||||||
ffmpeg.input('in')
|
ffmpeg.input('in')
|
||||||
.drawtext('test', font='a{}b'.format(font))
|
.drawtext('test', font='a{}b'.format(font))
|
||||||
@ -370,7 +390,9 @@ def test_filter_normal_arg_escape():
|
|||||||
assert args[:3] == ['-i', 'in', '-filter_complex']
|
assert args[:3] == ['-i', 'in', '-filter_complex']
|
||||||
assert args[4:] == ['-map', '[s0]', 'out']
|
assert args[4:] == ['-map', '[s0]', 'out']
|
||||||
match = re.match(
|
match = re.match(
|
||||||
r'\[0\]drawtext=font=a((.|\n)*)b:text=test\[s0\]', args[3], re.MULTILINE
|
r'\[0\]drawtext=font=a((.|\n)*)b:text=test\[s0\]',
|
||||||
|
args[3],
|
||||||
|
re.MULTILINE,
|
||||||
)
|
)
|
||||||
assert match is not None, 'Invalid -filter_complex arg: {!r}'.format(args[3])
|
assert match is not None, 'Invalid -filter_complex arg: {!r}'.format(args[3])
|
||||||
return match.group(1)
|
return match.group(1)
|
||||||
@ -394,10 +416,14 @@ def test_filter_normal_arg_escape():
|
|||||||
|
|
||||||
|
|
||||||
def test_filter_text_arg_str_escape():
|
def test_filter_text_arg_str_escape():
|
||||||
"""Test string escaping of normal filter args (e.g. ``text`` param of ``drawtext`` filter)."""
|
"""Test string escaping of normal filter args (e.g. ``text`` param of ``drawtext``
|
||||||
|
filter).
|
||||||
|
"""
|
||||||
|
|
||||||
def _get_drawtext_text_repr(text):
|
def _get_drawtext_text_repr(text):
|
||||||
"""Build a command-line arg using drawtext ``text`` param and extract the ``-filter_complex`` arg."""
|
"""Build a command-line arg using drawtext ``text`` param and extract the
|
||||||
|
``-filter_complex`` arg.
|
||||||
|
"""
|
||||||
args = ffmpeg.input('in').drawtext('a{}b'.format(text)).output('out').get_args()
|
args = ffmpeg.input('in').drawtext('a{}b'.format(text)).output('out').get_args()
|
||||||
assert args[:3] == ['-i', 'in', '-filter_complex']
|
assert args[:3] == ['-i', 'in', '-filter_complex']
|
||||||
assert args[4:] == ['-map', '[s0]', 'out']
|
assert args[4:] == ['-map', '[s0]', 'out']
|
||||||
@ -447,8 +473,11 @@ def test__run_async(mocker, pipe_stdin, pipe_stdout, pipe_stderr, cwd):
|
|||||||
popen__mock = mocker.patch.object(subprocess, 'Popen', return_value=process__mock)
|
popen__mock = mocker.patch.object(subprocess, 'Popen', return_value=process__mock)
|
||||||
stream = _get_simple_example()
|
stream = _get_simple_example()
|
||||||
process = ffmpeg.run_async(
|
process = ffmpeg.run_async(
|
||||||
stream, pipe_stdin=pipe_stdin, pipe_stdout=pipe_stdout,
|
stream,
|
||||||
pipe_stderr=pipe_stderr, cwd=cwd
|
pipe_stdin=pipe_stdin,
|
||||||
|
pipe_stdout=pipe_stdout,
|
||||||
|
pipe_stderr=pipe_stderr,
|
||||||
|
cwd=cwd,
|
||||||
)
|
)
|
||||||
assert process is process__mock
|
assert process is process__mock
|
||||||
|
|
||||||
@ -458,8 +487,10 @@ def test__run_async(mocker, pipe_stdin, pipe_stdout, pipe_stderr, cwd):
|
|||||||
(args,), kwargs = popen__mock.call_args
|
(args,), kwargs = popen__mock.call_args
|
||||||
assert args == ffmpeg.compile(stream)
|
assert args == ffmpeg.compile(stream)
|
||||||
assert kwargs == dict(
|
assert kwargs == dict(
|
||||||
stdin=expected_stdin, stdout=expected_stdout, stderr=expected_stderr,
|
stdin=expected_stdin,
|
||||||
cwd=cwd
|
stdout=expected_stdout,
|
||||||
|
stderr=expected_stderr,
|
||||||
|
cwd=cwd,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -695,7 +726,10 @@ def test_pipe():
|
|||||||
|
|
||||||
cmd = ['ffmpeg'] + args
|
cmd = ['ffmpeg'] + args
|
||||||
p = subprocess.Popen(
|
p = subprocess.Popen(
|
||||||
cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
cmd,
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
)
|
)
|
||||||
|
|
||||||
in_data = bytes(
|
in_data = bytes(
|
||||||
@ -715,10 +749,10 @@ def test__probe():
|
|||||||
assert data['format']['duration'] == '7.036000'
|
assert data['format']['duration'] == '7.036000'
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(sys.version_info < (3, 3), reason="requires python3.3 or higher")
|
@pytest.mark.skipif(sys.version_info < (3, 3), reason='requires python3.3 or higher')
|
||||||
def test__probe_timeout():
|
def test__probe_timeout():
|
||||||
with pytest.raises(subprocess.TimeoutExpired) as excinfo:
|
with pytest.raises(subprocess.TimeoutExpired) as excinfo:
|
||||||
data = ffmpeg.probe(TEST_INPUT_FILE1, timeout=0)
|
ffmpeg.probe(TEST_INPUT_FILE1, timeout=0)
|
||||||
assert 'timed out after 0 seconds' in str(excinfo.value)
|
assert 'timed out after 0 seconds' in str(excinfo.value)
|
||||||
|
|
||||||
|
|
||||||
@ -751,24 +785,24 @@ def get_filter_complex_outputs(flt, name):
|
|||||||
|
|
||||||
|
|
||||||
def test__get_filter_complex_input():
|
def test__get_filter_complex_input():
|
||||||
assert get_filter_complex_input("", "scale") is None
|
assert get_filter_complex_input('', 'scale') is None
|
||||||
assert get_filter_complex_input("scale", "scale") is None
|
assert get_filter_complex_input('scale', 'scale') is None
|
||||||
assert get_filter_complex_input("scale[s3][s4];etc", "scale") is None
|
assert get_filter_complex_input('scale[s3][s4];etc', 'scale') is None
|
||||||
assert get_filter_complex_input("[s2]scale", "scale") == "s2"
|
assert get_filter_complex_input('[s2]scale', 'scale') == 's2'
|
||||||
assert get_filter_complex_input("[s2]scale;etc", "scale") == "s2"
|
assert get_filter_complex_input('[s2]scale;etc', 'scale') == 's2'
|
||||||
assert get_filter_complex_input("[s2]scale[s3][s4];etc", "scale") == "s2"
|
assert get_filter_complex_input('[s2]scale[s3][s4];etc', 'scale') == 's2'
|
||||||
|
|
||||||
|
|
||||||
def test__get_filter_complex_outputs():
|
def test__get_filter_complex_outputs():
|
||||||
assert get_filter_complex_outputs("", "scale") is None
|
assert get_filter_complex_outputs('', 'scale') is None
|
||||||
assert get_filter_complex_outputs("scale", "scale") is None
|
assert get_filter_complex_outputs('scale', 'scale') is None
|
||||||
assert get_filter_complex_outputs("scalex[s0][s1]", "scale") is None
|
assert get_filter_complex_outputs('scalex[s0][s1]', 'scale') is None
|
||||||
assert get_filter_complex_outputs("scale[s0][s1]", "scale") == ['s0', 's1']
|
assert get_filter_complex_outputs('scale[s0][s1]', 'scale') == ['s0', 's1']
|
||||||
assert get_filter_complex_outputs("[s5]scale[s0][s1]", "scale") == ['s0', 's1']
|
assert get_filter_complex_outputs('[s5]scale[s0][s1]', 'scale') == ['s0', 's1']
|
||||||
assert get_filter_complex_outputs("[s5]scale[s1][s0]", "scale") == ['s1', 's0']
|
assert get_filter_complex_outputs('[s5]scale[s1][s0]', 'scale') == ['s1', 's0']
|
||||||
assert get_filter_complex_outputs("[s5]scale[s1]", "scale") == ['s1']
|
assert get_filter_complex_outputs('[s5]scale[s1]', 'scale') == ['s1']
|
||||||
assert get_filter_complex_outputs("[s5]scale[s1];x", "scale") == ['s1']
|
assert get_filter_complex_outputs('[s5]scale[s1];x', 'scale') == ['s1']
|
||||||
assert get_filter_complex_outputs("y;[s5]scale[s1];x", "scale") == ['s1']
|
assert get_filter_complex_outputs('y;[s5]scale[s1];x', 'scale') == ['s1']
|
||||||
|
|
||||||
|
|
||||||
def test__multi_output_edge_label_order():
|
def test__multi_output_edge_label_order():
|
||||||
|
15
pyproject.toml
Normal file
15
pyproject.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[tool.black]
|
||||||
|
skip-string-normalization = true
|
||||||
|
target_version = ['py27'] # TODO: drop Python 2 support (... "Soon").
|
||||||
|
include = '\.pyi?$'
|
||||||
|
exclude = '''
|
||||||
|
(
|
||||||
|
/(
|
||||||
|
\.eggs
|
||||||
|
| \.git
|
||||||
|
| \.tox
|
||||||
|
| \venv
|
||||||
|
| dist
|
||||||
|
)/
|
||||||
|
)
|
||||||
|
'''
|
Loading…
x
Reference in New Issue
Block a user