Source code for mendevi.cmd
"""Allow to handle ffmpeg command line."""
import pathlib
import shlex
[docs]
class CmdFFMPEG:
"""Allow easy manipulation of a complete ffmpeg expression.
ffmpeg -y -hide_banner -loglevel verbose
Attributes
----------
decode : list[str]
The options between -c:v and -i (read and write).
vid_filter : str
The filter string after -vf (read and write).
general : list[str]
The options immediately after ffmpeg and immediately before the decoder (read and write).
video : pathlib.Path
The input video path (readonly).
encode : list[str]
The encoder name and options after -c:v (read and write).
"""
def __init__(
self,
video: pathlib.Path | str,
general: list[str] | str | None = None,
decode: list[str] | str | None = None,
vid_filter: str = "",
encode: list[str] | str | None = None,
) -> None:
"""Initialise the ffmpeg cmd.
Parameters
----------
video : pathlike
The input video path.
general : list[str], str, optional
The options immediately after ffmpeg and immediately before the decoder.
decode : list[str], str, optional
The options between -c:v and -i.
vid_filter : str, optional
The filter string after -vf.
encode: list[str], str, optional
The encoder name and options after -c:v.
"""
video = pathlib.Path(video).expanduser()
self._video = video
self._general = self._decode = self._vid_filter = self._encode = None # initialisation
self.general = general # setter
self.decode = decode
self.vid_filter = vid_filter
self.encode = encode
@property
def decode(self) -> list[str]:
"""Return the options between -c:v and -i."""
return self._decode.copy()
@decode.setter
def decode(self, decode: list[str] | str | None) -> None:
"""Update the options between -c:v and -i."""
match decode:
case None:
self._decode = []
case str():
self._decode = shlex.split(decode)
case list():
assert all(isinstance(cmd, str) for cmd in decode), decode
self._decode = decode.copy()
case _:
msg = f"'decode' has to be None, str or list, not {decode.__class__.__name__}"
raise TypeError(msg)
@property
def encode(self) -> list[str]:
"""Return the encoder name and options after -c:v."""
return self._encode.copy()
@encode.setter
def encode(self, encode: list[str] | str | None) -> None:
"""Update the encoder name and options after -c:v."""
match encode:
case None:
self._encode = []
case str():
self._encode = shlex.split(encode)
case list():
assert all(isinstance(cmd, str) for cmd in encode), encode
self._encode = encode.copy()
case _:
msg = f"'encode' has to be None, str or list, not {encode.__class__.__name__}"
raise TypeError(msg)
@property
def vid_filter(self) -> str:
"""Return the filter string after -vf."""
return self._filter
@vid_filter.setter
def vid_filter(self, vid_filter: str) -> None:
"""Update the filter string after -vf."""
assert isinstance(vid_filter, str), vid_filter.__class__.__name__
self._vid_filter = vid_filter
@property
def general(self) -> list[str]:
"""Return the options immediately after ffmpeg and immediately before the decoder."""
if self._general is None:
return ["-y", "-log_verbose"]
return self._general.copy()
@general.setter
def general(self, general: list[str] | str | None) -> None:
"""Update the options immediately after ffmpeg and immediately before the decoder."""
match general:
case None:
self._general = None
case str():
self._general = shlex.split(general)
case list():
assert all(isinstance(cmd, str) for cmd in general), general
self._general = general.copy()
case _:
msg = f"'general' has to be None, str or list, not {general.__class__.__name__}"
raise TypeError(msg)
@property
def video(self) -> pathlib.Path:
"""Return the input video path."""
return self._video
def __iter__(self) -> str:
"""Iterate over each parameter to be compatible with list(self)."""
yield "ffmpeg"
yield from self.general
if self._decode:
yield "-c:v"
yield from self._decode
yield "-i"
yield str(self._video)
if self._vid_filter:
yield "-vf"
yield self._vid_filter
if self._encode:
yield "-c:v"
yield from self._encode
yield from ("-f", "null", "-")
def __str__(self) -> str:
"""Return the full shell cmd.
Examples
--------
>>> from mendevi.cmd import CmdFFMPEG
>>> print(CmdFFMPEG(video="src.mp4"))
ffmpeg -y -log_verbose -i src.mp4 -f null -
>>>
"""
return " ".join(map(shlex.quote, self))