typed-ffmpeg-compatible 2.6.2__py3-none-any.whl → 2.6.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- typed_ffmpeg/__init__.py +26 -1
- typed_ffmpeg/base.py +87 -29
- typed_ffmpeg/common/schema.py +281 -3
- typed_ffmpeg/common/serialize.py +118 -21
- typed_ffmpeg/dag/__init__.py +13 -0
- typed_ffmpeg/dag/compile.py +39 -4
- typed_ffmpeg/dag/context.py +137 -29
- typed_ffmpeg/dag/factory.py +27 -0
- typed_ffmpeg/dag/global_runnable/global_args.py +11 -0
- typed_ffmpeg/dag/global_runnable/runnable.py +143 -34
- typed_ffmpeg/dag/io/_input.py +2 -1
- typed_ffmpeg/dag/io/_output.py +2 -1
- typed_ffmpeg/dag/nodes.py +402 -67
- typed_ffmpeg/dag/schema.py +3 -1
- typed_ffmpeg/dag/utils.py +29 -8
- typed_ffmpeg/dag/validate.py +83 -20
- typed_ffmpeg/exceptions.py +42 -9
- typed_ffmpeg/info.py +137 -16
- typed_ffmpeg/probe.py +31 -6
- typed_ffmpeg/schema.py +32 -5
- typed_ffmpeg/sources.py +2825 -0
- typed_ffmpeg/streams/channel_layout.py +13 -0
- typed_ffmpeg/utils/escaping.py +47 -7
- typed_ffmpeg/utils/forzendict.py +108 -0
- typed_ffmpeg/utils/lazy_eval/operator.py +43 -1
- typed_ffmpeg/utils/lazy_eval/schema.py +122 -6
- typed_ffmpeg/utils/run.py +44 -7
- typed_ffmpeg/utils/snapshot.py +36 -1
- typed_ffmpeg/utils/typing.py +29 -4
- typed_ffmpeg/utils/view.py +46 -4
- {typed_ffmpeg_compatible-2.6.2.dist-info → typed_ffmpeg_compatible-2.6.4.dist-info}/METADATA +1 -1
- typed_ffmpeg_compatible-2.6.4.dist-info/RECORD +48 -0
- typed_ffmpeg_compatible-2.6.2.dist-info/RECORD +0 -46
- {typed_ffmpeg_compatible-2.6.2.dist-info → typed_ffmpeg_compatible-2.6.4.dist-info}/LICENSE +0 -0
- {typed_ffmpeg_compatible-2.6.2.dist-info → typed_ffmpeg_compatible-2.6.4.dist-info}/WHEEL +0 -0
- {typed_ffmpeg_compatible-2.6.2.dist-info → typed_ffmpeg_compatible-2.6.4.dist-info}/entry_points.txt +0 -0
@@ -1,3 +1,16 @@
|
|
1
|
+
"""
|
2
|
+
Audio channel layout definitions for FFmpeg.
|
3
|
+
|
4
|
+
This module defines a mapping between FFmpeg's channel layout names and
|
5
|
+
the corresponding number of audio channels. This information is used for
|
6
|
+
audio stream processing, filtering, and conversion operations.
|
7
|
+
|
8
|
+
Channel layouts in FFmpeg represent different speaker configurations,
|
9
|
+
such as mono (1 channel), stereo (2 channels), 5.1 (6 channels), etc.
|
10
|
+
The names used in this dictionary match the standard names used by FFmpeg's
|
11
|
+
channel layout API.
|
12
|
+
"""
|
13
|
+
|
1
14
|
CHANNEL_LAYOUT = {
|
2
15
|
"mono": 1,
|
3
16
|
"stereo": 2,
|
typed_ffmpeg/utils/escaping.py
CHANGED
@@ -1,17 +1,39 @@
|
|
1
|
+
"""
|
2
|
+
Utilities for escaping special characters in FFmpeg command arguments.
|
3
|
+
|
4
|
+
This module provides functions for properly escaping special characters in
|
5
|
+
FFmpeg command-line arguments and converting Python dictionaries to FFmpeg
|
6
|
+
command-line parameter formats.
|
7
|
+
"""
|
8
|
+
|
1
9
|
from collections.abc import Iterable
|
2
10
|
from typing import Any
|
3
11
|
|
4
12
|
|
5
13
|
def escape(text: str | int | float, chars: str = "\\'=:") -> str:
|
6
14
|
"""
|
7
|
-
|
15
|
+
Escape special characters in a string for use in FFmpeg commands.
|
16
|
+
|
17
|
+
This function adds backslash escaping to specified characters in a string,
|
18
|
+
making it safe to use in FFmpeg filter strings and command-line arguments
|
19
|
+
where certain characters have special meaning.
|
8
20
|
|
9
21
|
Args:
|
10
|
-
text: The text to escape
|
11
|
-
chars:
|
22
|
+
text: The text to escape (will be converted to string if not already)
|
23
|
+
chars: A string containing all characters that should be escaped
|
24
|
+
(default: "\\'=:" which handles most common special chars in FFmpeg)
|
12
25
|
|
13
26
|
Returns:
|
14
|
-
The escaped
|
27
|
+
The input text with all specified characters escaped with backslashes
|
28
|
+
|
29
|
+
Example:
|
30
|
+
```python
|
31
|
+
# Escape a filename with spaces for FFmpeg
|
32
|
+
safe_filename = escape("input file.mp4") # "input\\ file.mp4"
|
33
|
+
|
34
|
+
# Escape a filter parameter value
|
35
|
+
safe_value = escape("key=value", "=:") # "key\\=value"
|
36
|
+
```
|
15
37
|
"""
|
16
38
|
text = str(text)
|
17
39
|
_chars = list(set(chars))
|
@@ -27,13 +49,31 @@ def escape(text: str | int | float, chars: str = "\\'=:") -> str:
|
|
27
49
|
|
28
50
|
def convert_kwargs_to_cmd_line_args(kwargs: dict[str, Any]) -> list[str]:
|
29
51
|
"""
|
30
|
-
|
52
|
+
Convert a Python dictionary to FFmpeg command-line arguments.
|
53
|
+
|
54
|
+
This function takes a dictionary of parameter names and values and converts
|
55
|
+
them to a list of strings in the format expected by FFmpeg command-line tools.
|
56
|
+
Each key becomes a parameter prefixed with '-', and its value follows as a
|
57
|
+
separate argument.
|
31
58
|
|
32
59
|
Args:
|
33
|
-
kwargs:
|
60
|
+
kwargs: Dictionary mapping parameter names to their values
|
34
61
|
|
35
62
|
Returns:
|
36
|
-
|
63
|
+
A list of strings representing FFmpeg command-line arguments
|
64
|
+
|
65
|
+
Example:
|
66
|
+
```python
|
67
|
+
args = convert_kwargs_to_cmd_line_args(
|
68
|
+
{"c:v": "libx264", "crf": 23, "preset": "medium"}
|
69
|
+
)
|
70
|
+
# Returns ['-c:v', 'libx264', '-crf', '23', '-preset', 'medium']
|
71
|
+
```
|
72
|
+
|
73
|
+
Note:
|
74
|
+
If a value is None, only the parameter name is included.
|
75
|
+
If a value is an iterable (but not a string), the parameter is repeated
|
76
|
+
for each value in the iterable.
|
37
77
|
"""
|
38
78
|
args = []
|
39
79
|
for k in sorted(kwargs.keys()):
|
@@ -0,0 +1,108 @@
|
|
1
|
+
"""
|
2
|
+
Provides an immutable dictionary implementation.
|
3
|
+
|
4
|
+
This module implements a frozen (immutable) dictionary class that can be used
|
5
|
+
where hashable dictionaries are needed, such as in sets or as keys in other
|
6
|
+
dictionaries. Once created, a FrozenDict cannot be modified.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from collections.abc import Iterator, Mapping
|
10
|
+
from typing import Any, Generic, TypeVar
|
11
|
+
|
12
|
+
K = TypeVar("K")
|
13
|
+
V = TypeVar("V")
|
14
|
+
|
15
|
+
|
16
|
+
class FrozenDict(Mapping[K, V], Generic[K, V]):
|
17
|
+
"""
|
18
|
+
An immutable dictionary implementation.
|
19
|
+
|
20
|
+
FrozenDict provides a hashable, immutable view of a dictionary. It implements
|
21
|
+
the Mapping interface but does not allow modification after creation.
|
22
|
+
This makes it suitable for use as dictionary keys or in sets where
|
23
|
+
mutability would cause issues.
|
24
|
+
"""
|
25
|
+
|
26
|
+
def __init__(self, data: dict[K, V]):
|
27
|
+
"""
|
28
|
+
Initialize a FrozenDict with the provided dictionary data.
|
29
|
+
|
30
|
+
Args:
|
31
|
+
data: Dictionary to create a frozen copy of
|
32
|
+
"""
|
33
|
+
self._data = dict(data)
|
34
|
+
self._hash: int | None = None # lazy computed
|
35
|
+
|
36
|
+
def __getitem__(self, key: K) -> V:
|
37
|
+
"""
|
38
|
+
Retrieve a value from the dictionary by key.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
key: The key to look up
|
42
|
+
|
43
|
+
Returns:
|
44
|
+
The value associated with the key
|
45
|
+
|
46
|
+
Raises:
|
47
|
+
KeyError: If the key is not found
|
48
|
+
"""
|
49
|
+
return self._data[key]
|
50
|
+
|
51
|
+
def __iter__(self) -> Iterator[K]:
|
52
|
+
"""
|
53
|
+
Return an iterator over the dictionary keys.
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
An iterator yielding the dictionary keys
|
57
|
+
"""
|
58
|
+
return iter(self._data)
|
59
|
+
|
60
|
+
def __len__(self) -> int:
|
61
|
+
"""
|
62
|
+
Return the number of items in the dictionary.
|
63
|
+
|
64
|
+
Returns:
|
65
|
+
The number of key-value pairs in the dictionary
|
66
|
+
"""
|
67
|
+
return len(self._data)
|
68
|
+
|
69
|
+
def __repr__(self) -> str:
|
70
|
+
"""
|
71
|
+
Return a string representation of the FrozenDict.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
A string representation showing the dictionary contents
|
75
|
+
"""
|
76
|
+
return f"FrozenDict({self._data})"
|
77
|
+
|
78
|
+
def __eq__(self, other: Any) -> bool:
|
79
|
+
"""
|
80
|
+
Compare this FrozenDict with another object for equality.
|
81
|
+
|
82
|
+
Two FrozenDicts are equal if they contain the same key-value pairs.
|
83
|
+
A FrozenDict can also be equal to other Mapping objects with the same contents.
|
84
|
+
|
85
|
+
Args:
|
86
|
+
other: Object to compare with
|
87
|
+
|
88
|
+
Returns:
|
89
|
+
True if the objects are equal, False otherwise
|
90
|
+
"""
|
91
|
+
if isinstance(other, Mapping):
|
92
|
+
return dict(self._data) == dict(other)
|
93
|
+
return NotImplemented
|
94
|
+
|
95
|
+
def __hash__(self) -> int:
|
96
|
+
"""
|
97
|
+
Compute a hash value for this FrozenDict.
|
98
|
+
|
99
|
+
The hash is lazily computed the first time it's needed and then cached.
|
100
|
+
This makes FrozenDict usable as a dictionary key or in sets.
|
101
|
+
|
102
|
+
Returns:
|
103
|
+
An integer hash value
|
104
|
+
"""
|
105
|
+
if self._hash is None:
|
106
|
+
# Create a stable hash based on sorted key-value pairs
|
107
|
+
self._hash = hash(frozenset(self._data.items()))
|
108
|
+
return self._hash
|
@@ -1,3 +1,12 @@
|
|
1
|
+
"""
|
2
|
+
Concrete operator implementations for lazy evaluation expressions.
|
3
|
+
|
4
|
+
This module defines the specific operator classes that implement the LazyOperator
|
5
|
+
abstract base class. Each class represents a mathematical operation like addition,
|
6
|
+
subtraction, multiplication, etc., and provides the implementation for evaluating
|
7
|
+
that operation when all required values are available.
|
8
|
+
"""
|
9
|
+
|
1
10
|
from dataclasses import dataclass
|
2
11
|
from typing import Any
|
3
12
|
|
@@ -7,13 +16,46 @@ from .schema import LazyOperator
|
|
7
16
|
@dataclass(frozen=True, kw_only=True)
|
8
17
|
class Add(LazyOperator):
|
9
18
|
"""
|
10
|
-
A lazy operator for addition.
|
19
|
+
A lazy operator for addition operations.
|
20
|
+
|
21
|
+
This class implements the addition operation for lazy evaluation expressions.
|
22
|
+
It evaluates to the sum of its left and right operands when all required
|
23
|
+
values are available.
|
24
|
+
|
25
|
+
Example:
|
26
|
+
```python
|
27
|
+
# Create an expression that adds width and height
|
28
|
+
from .schema import Symbol
|
29
|
+
|
30
|
+
width = Symbol("width")
|
31
|
+
height = Symbol("height")
|
32
|
+
expr = Add(left=width, right=height)
|
33
|
+
|
34
|
+
# Evaluate the expression with specific values
|
35
|
+
result = expr.eval(width=1280, height=720) # Returns 2000
|
36
|
+
```
|
11
37
|
"""
|
12
38
|
|
13
39
|
def _eval(self, left: Any, right: Any) -> Any:
|
40
|
+
"""
|
41
|
+
Evaluate the addition operation with the given operands.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
left: The left operand
|
45
|
+
right: The right operand
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
The sum of the left and right operands
|
49
|
+
"""
|
14
50
|
return left + right
|
15
51
|
|
16
52
|
def __str__(self) -> str:
|
53
|
+
"""
|
54
|
+
Get a string representation of this addition operation.
|
55
|
+
|
56
|
+
Returns:
|
57
|
+
A string in the format "(left+right)"
|
58
|
+
"""
|
17
59
|
return f"({self.left}+{self.right})"
|
18
60
|
|
19
61
|
|
@@ -1,3 +1,13 @@
|
|
1
|
+
"""
|
2
|
+
Schema for lazy evaluation of expressions in FFmpeg filter parameters.
|
3
|
+
|
4
|
+
This module defines the core classes for lazy evaluation of expressions in
|
5
|
+
FFmpeg filter parameters. It provides a way to represent expressions that
|
6
|
+
can be evaluated at a later time, when all required values are available.
|
7
|
+
This is particularly useful for parameters that depend on runtime information
|
8
|
+
or need to be computed based on other parameters.
|
9
|
+
"""
|
10
|
+
|
1
11
|
from __future__ import annotations
|
2
12
|
|
3
13
|
from abc import ABC, abstractmethod
|
@@ -9,7 +19,15 @@ from ..typing import override
|
|
9
19
|
|
10
20
|
class LazyValue(ABC):
|
11
21
|
"""
|
12
|
-
|
22
|
+
Abstract base class for lazy evaluation of expressions.
|
23
|
+
|
24
|
+
LazyValue represents an expression that can be evaluated at a later time,
|
25
|
+
when all required values are available. It supports various arithmetic
|
26
|
+
operations, allowing complex expressions to be built and evaluated lazily.
|
27
|
+
|
28
|
+
This class serves as the foundation for the lazy evaluation system, with
|
29
|
+
concrete implementations like Symbol and LazyOperator providing specific
|
30
|
+
functionality.
|
13
31
|
"""
|
14
32
|
|
15
33
|
def __add__(self, v: Any) -> LazyValue:
|
@@ -132,6 +150,14 @@ class LazyValue(ABC):
|
|
132
150
|
def ready(self) -> bool:
|
133
151
|
"""
|
134
152
|
Check if the lazy value is ready to be evaluated.
|
153
|
+
|
154
|
+
A lazy value is considered ready for evaluation when it doesn't require
|
155
|
+
any additional values to be provided. This is determined by checking if
|
156
|
+
the set of required keys is empty.
|
157
|
+
|
158
|
+
Returns:
|
159
|
+
True if the lazy value can be evaluated without additional values,
|
160
|
+
False otherwise
|
135
161
|
"""
|
136
162
|
return not self.keys()
|
137
163
|
|
@@ -139,6 +165,14 @@ class LazyValue(ABC):
|
|
139
165
|
def keys(self) -> set[str]:
|
140
166
|
"""
|
141
167
|
Get the keys that are required to evaluate the lazy value.
|
168
|
+
|
169
|
+
This method returns the set of symbol names that must be provided
|
170
|
+
as values for the lazy value to be fully evaluated. For example,
|
171
|
+
if the lazy value represents the expression 'width * height',
|
172
|
+
this method would return {'width', 'height'}.
|
173
|
+
|
174
|
+
Returns:
|
175
|
+
A set of strings representing the required symbol names
|
142
176
|
"""
|
143
177
|
...
|
144
178
|
|
@@ -146,33 +180,80 @@ class LazyValue(ABC):
|
|
146
180
|
@dataclass(frozen=True)
|
147
181
|
class Symbol(LazyValue):
|
148
182
|
"""
|
149
|
-
A symbol that represents a variable in
|
183
|
+
A symbol that represents a variable in lazy evaluation expressions.
|
184
|
+
|
185
|
+
Symbol is a concrete implementation of LazyValue that represents a named
|
186
|
+
variable in an expression. When evaluating the expression, the actual value
|
187
|
+
of the symbol is provided through a dictionary of values.
|
188
|
+
|
189
|
+
Examples of symbols include variable names like 'width', 'height', or any
|
190
|
+
other parameter that will be provided at evaluation time rather than at
|
191
|
+
expression creation time.
|
150
192
|
|
151
|
-
|
193
|
+
Attributes:
|
194
|
+
key: The name of the variable this symbol represents
|
152
195
|
"""
|
153
196
|
|
154
197
|
key: str
|
155
198
|
|
156
199
|
def __str__(self) -> str:
|
200
|
+
"""
|
201
|
+
Get a string representation of this symbol.
|
202
|
+
|
203
|
+
Returns:
|
204
|
+
The symbol's key as a string
|
205
|
+
"""
|
157
206
|
return str(self.key)
|
158
207
|
|
159
208
|
@override
|
160
209
|
def partial(self, **values: Any) -> Any:
|
210
|
+
"""
|
211
|
+
Partially evaluate this symbol with the given values.
|
212
|
+
|
213
|
+
If the symbol's key is present in the values dictionary, returns the
|
214
|
+
corresponding value. Otherwise, returns the symbol itself (unchanged).
|
215
|
+
|
216
|
+
Args:
|
217
|
+
**values: Dictionary mapping symbol names to their values
|
218
|
+
|
219
|
+
Returns:
|
220
|
+
The value for this symbol if available, otherwise the symbol itself
|
221
|
+
"""
|
161
222
|
if self.key in values:
|
162
223
|
return values[self.key]
|
163
224
|
return self
|
164
225
|
|
165
226
|
@override
|
166
227
|
def keys(self) -> set[str]:
|
228
|
+
"""
|
229
|
+
Get the set of symbol names required to evaluate this symbol.
|
230
|
+
|
231
|
+
For a Symbol, this is simply a set containing its own key.
|
232
|
+
|
233
|
+
Returns:
|
234
|
+
A set containing the symbol's key
|
235
|
+
"""
|
167
236
|
return {self.key}
|
168
237
|
|
169
238
|
|
170
239
|
@dataclass(frozen=True, kw_only=True)
|
171
240
|
class LazyOperator(LazyValue):
|
172
241
|
"""
|
173
|
-
|
242
|
+
Abstract base class for operators in lazy evaluation expressions.
|
243
|
+
|
244
|
+
LazyOperator is an abstract implementation of LazyValue that represents
|
245
|
+
mathematical operations in an expression. Concrete subclasses implement
|
246
|
+
specific operations like addition, subtraction, multiplication, etc.
|
247
|
+
|
248
|
+
This class provides the common structure and behavior for all operators,
|
249
|
+
including handling of operands that may themselves be LazyValues.
|
174
250
|
|
175
|
-
|
251
|
+
Attributes:
|
252
|
+
left: The left operand of the operation (or the only operand for unary operations)
|
253
|
+
right: The right operand of the operation (None for unary operations)
|
254
|
+
|
255
|
+
Concrete implementations include:
|
256
|
+
Add, Sub, Mul, TrueDiv, Pow, Neg, Pos, Abs, Mod, FloorDiv
|
176
257
|
"""
|
177
258
|
|
178
259
|
left: Any = None
|
@@ -181,12 +262,37 @@ class LazyOperator(LazyValue):
|
|
181
262
|
@abstractmethod
|
182
263
|
def _eval(self, left: Any, right: Any) -> Any:
|
183
264
|
"""
|
184
|
-
Evaluate the operator with the given values.
|
265
|
+
Evaluate the operator with the given operand values.
|
266
|
+
|
267
|
+
This abstract method must be implemented by concrete operator subclasses
|
268
|
+
to define the specific operation to perform (e.g., addition, multiplication).
|
269
|
+
|
270
|
+
Args:
|
271
|
+
left: The evaluated left operand (or only operand for unary operations)
|
272
|
+
right: The evaluated right operand (may be None for unary operations)
|
273
|
+
|
274
|
+
Returns:
|
275
|
+
The result of applying the operation to the operands
|
185
276
|
"""
|
186
277
|
...
|
187
278
|
|
188
279
|
@override
|
189
280
|
def partial(self, **values: Any) -> Any:
|
281
|
+
"""
|
282
|
+
Partially evaluate this operator with the given values.
|
283
|
+
|
284
|
+
This method recursively evaluates the operands (which may themselves be
|
285
|
+
LazyValues) with the provided values, then applies the operator's
|
286
|
+
specific operation to the results.
|
287
|
+
|
288
|
+
Args:
|
289
|
+
**values: Dictionary mapping symbol names to their values
|
290
|
+
|
291
|
+
Returns:
|
292
|
+
The result of applying the operation to the partially evaluated operands,
|
293
|
+
which may be a concrete value or another LazyValue if some symbols
|
294
|
+
remain unevaluated
|
295
|
+
"""
|
190
296
|
if isinstance(self.left, LazyValue):
|
191
297
|
left = self.left.partial(**values)
|
192
298
|
else:
|
@@ -201,6 +307,16 @@ class LazyOperator(LazyValue):
|
|
201
307
|
|
202
308
|
@override
|
203
309
|
def keys(self) -> set[str]:
|
310
|
+
"""
|
311
|
+
Get the set of symbol names required to evaluate this operator.
|
312
|
+
|
313
|
+
This method collects the required symbol names from both operands
|
314
|
+
(if they are LazyValues) and returns their union.
|
315
|
+
|
316
|
+
Returns:
|
317
|
+
A set of strings representing all symbol names required to
|
318
|
+
fully evaluate this operator
|
319
|
+
"""
|
204
320
|
r = set()
|
205
321
|
if isinstance(self.left, LazyValue):
|
206
322
|
r |= self.left.keys()
|
typed_ffmpeg/utils/run.py
CHANGED
@@ -1,27 +1,64 @@
|
|
1
|
+
"""
|
2
|
+
Utilities for executing FFmpeg commands and handling command arguments.
|
3
|
+
|
4
|
+
This module provides helper functions for formatting command-line arguments,
|
5
|
+
filtering default values, and preparing options for command execution.
|
6
|
+
"""
|
7
|
+
|
1
8
|
import shlex
|
9
|
+
from collections.abc import Mapping
|
2
10
|
|
3
11
|
from ..schema import Default
|
4
12
|
from ..utils.lazy_eval.schema import LazyValue
|
13
|
+
from .forzendict import FrozenDict
|
5
14
|
|
6
15
|
|
7
16
|
def command_line(args: list[str]) -> str:
|
8
17
|
"""
|
9
|
-
|
18
|
+
Convert a list of command arguments to a properly escaped command-line string.
|
19
|
+
|
20
|
+
This function takes a list of command arguments and converts it to a single
|
21
|
+
string with proper shell escaping applied to each argument. This is useful
|
22
|
+
for logging commands or displaying them to users.
|
10
23
|
|
11
24
|
Args:
|
12
|
-
args: The arguments to convert
|
25
|
+
args: The command arguments to convert to a string
|
13
26
|
|
14
27
|
Returns:
|
15
|
-
|
28
|
+
A properly escaped command-line string representation of the arguments
|
29
|
+
|
30
|
+
Example:
|
31
|
+
```python
|
32
|
+
cmd = ["ffmpeg", "-i", "input file.mp4", "-c:v", "libx264"]
|
33
|
+
print(command_line(cmd)) # 'ffmpeg -i "input file.mp4" -c:v libx264'
|
34
|
+
```
|
16
35
|
"""
|
17
36
|
return " ".join(shlex.quote(arg) for arg in args)
|
18
37
|
|
19
38
|
|
20
39
|
# Filter_Node_Option_Type
|
21
40
|
def ignore_default(
|
22
|
-
kwargs:
|
23
|
-
) ->
|
41
|
+
kwargs: Mapping[str, str | int | float | bool | Default],
|
42
|
+
) -> FrozenDict[str, str | int | float | bool | LazyValue]:
|
24
43
|
"""
|
25
|
-
|
44
|
+
Filter out Default values from a dictionary of options.
|
45
|
+
|
46
|
+
This function is used to process FFmpeg filter options and command arguments,
|
47
|
+
removing any values that are instances of the Default class. This ensures
|
48
|
+
that only explicitly set options are passed to FFmpeg, allowing default values
|
49
|
+
to be applied by FFmpeg itself.
|
50
|
+
|
51
|
+
Args:
|
52
|
+
kwargs: A mapping containing parameter names and values,
|
53
|
+
which may include Default instances
|
54
|
+
|
55
|
+
Returns:
|
56
|
+
An immutable FrozenDict containing only non-Default values
|
57
|
+
|
58
|
+
Example:
|
59
|
+
```python
|
60
|
+
options = {"width": 1920, "height": 1080, "format": Default("yuv420p")}
|
61
|
+
filtered = ignore_default(options) # {"width": 1920, "height": 1080}
|
62
|
+
```
|
26
63
|
"""
|
27
|
-
return
|
64
|
+
return FrozenDict({k: v for k, v in kwargs.items() if not isinstance(v, Default)})
|
typed_ffmpeg/utils/snapshot.py
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
"""
|
2
|
+
Snapshot testing utilities for FFmpeg DAG structures.
|
3
|
+
|
4
|
+
This module provides extensions for the syrupy snapshot testing library that
|
5
|
+
enable serialization and testing of FFmpeg's Directed Acyclic Graph (DAG)
|
6
|
+
structures. It helps in writing tests that verify the correct structure and
|
7
|
+
behavior of filter graphs.
|
8
|
+
"""
|
9
|
+
|
1
10
|
from dataclasses import asdict
|
2
11
|
from typing import Optional
|
3
12
|
|
@@ -14,7 +23,16 @@ from ..dag.schema import Stream
|
|
14
23
|
|
15
24
|
class DAGSnapshotExtenstion(JSONSnapshotExtension):
|
16
25
|
"""
|
17
|
-
A snapshot extension for
|
26
|
+
A snapshot extension for serializing and testing FFmpeg DAG structures.
|
27
|
+
|
28
|
+
This extension extends the JSON snapshot extension from syrupy to handle
|
29
|
+
the special case of FFmpeg DAG nodes. It converts DAG nodes into a serializable
|
30
|
+
form suitable for snapshot testing by wrapping them in a Stream object and
|
31
|
+
converting to a dictionary.
|
32
|
+
|
33
|
+
This allows for robust testing of filter graph structures and ensures that
|
34
|
+
changes to the graph structure are intentional and documented through
|
35
|
+
snapshot testing.
|
18
36
|
"""
|
19
37
|
|
20
38
|
def serialize(
|
@@ -25,6 +43,23 @@ class DAGSnapshotExtenstion(JSONSnapshotExtension):
|
|
25
43
|
include: Optional["PropertyFilter"] = None,
|
26
44
|
matcher: Optional["PropertyMatcher"] = None,
|
27
45
|
) -> "SerializedData":
|
46
|
+
"""
|
47
|
+
Serialize a DAG node for snapshot testing.
|
48
|
+
|
49
|
+
This method converts a DAG node into a serializable format by wrapping
|
50
|
+
it in a Stream object and then converting that to a dictionary. This
|
51
|
+
approach ensures that all relevant properties of the node are captured
|
52
|
+
in the snapshot.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
data: The DAG node to serialize
|
56
|
+
exclude: Optional filter specifying properties to exclude
|
57
|
+
include: Optional filter specifying properties to include
|
58
|
+
matcher: Optional property matcher
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
The serialized representation of the DAG node
|
62
|
+
"""
|
28
63
|
stream = Stream(node=data)
|
29
64
|
|
30
65
|
return super().serialize(asdict(stream))
|
typed_ffmpeg/utils/typing.py
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
"""
|
2
|
+
Typing utilities for enhanced type annotations.
|
3
|
+
|
4
|
+
This module provides utilities for improving type annotations and enforcing
|
5
|
+
typing conventions within the codebase, offering better support for type checking
|
6
|
+
and documentation.
|
7
|
+
"""
|
8
|
+
|
1
9
|
from typing import TypeVar
|
2
10
|
|
3
11
|
V = TypeVar("V")
|
@@ -5,13 +13,30 @@ V = TypeVar("V")
|
|
5
13
|
|
6
14
|
def override(func: V) -> V:
|
7
15
|
"""
|
8
|
-
Decorator to indicate
|
9
|
-
|
16
|
+
Decorator to indicate a method that overrides a method in a superclass.
|
17
|
+
|
18
|
+
This decorator serves as a placeholder until Python 3.12, which introduces
|
19
|
+
a built-in @override decorator. Using this decorator helps with code clarity
|
20
|
+
and can catch errors where a method intended to override a parent class method
|
21
|
+
doesn't actually override anything (e.g., due to a typo in the method name).
|
10
22
|
|
11
23
|
Args:
|
12
|
-
func: The function to
|
24
|
+
func: The function to mark as an override of a superclass method
|
13
25
|
|
14
26
|
Returns:
|
15
|
-
The
|
27
|
+
The original function, unchanged (the decorator is used only for documentation)
|
28
|
+
|
29
|
+
Example:
|
30
|
+
```python
|
31
|
+
class Parent:
|
32
|
+
def method(self):
|
33
|
+
pass
|
34
|
+
|
35
|
+
|
36
|
+
class Child(Parent):
|
37
|
+
@override
|
38
|
+
def method(self): # Correctly overrides Parent.method
|
39
|
+
pass
|
40
|
+
```
|
16
41
|
"""
|
17
42
|
return func
|