typed-ffmpeg-compatible 3.2.2__py3-none-any.whl → 3.2.3__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/_version.py +2 -2
- typed_ffmpeg/compile/compile_cli.py +128 -20
- {typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/METADATA +1 -1
- {typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/RECORD +8 -8
- {typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/WHEEL +0 -0
- {typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/entry_points.txt +0 -0
- {typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/licenses/LICENSE +0 -0
- {typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/top_level.txt +0 -0
typed_ffmpeg/_version.py
CHANGED
@@ -47,11 +47,23 @@ from .validate import validate
|
|
47
47
|
|
48
48
|
|
49
49
|
def get_options_dict() -> dict[str, FFMpegOption]:
|
50
|
+
"""
|
51
|
+
Load and index FFmpeg options from the cache.
|
52
|
+
|
53
|
+
Returns:
|
54
|
+
Dictionary mapping option names to their FFMpegOption definitions
|
55
|
+
"""
|
50
56
|
options = load(list[FFMpegOption], "options")
|
51
57
|
return {option.name: option for option in options}
|
52
58
|
|
53
59
|
|
54
60
|
def get_filter_dict() -> dict[str, FFMpegFilter]:
|
61
|
+
"""
|
62
|
+
Load and index FFmpeg filters from the cache.
|
63
|
+
|
64
|
+
Returns:
|
65
|
+
Dictionary mapping filter names to their FFMpegFilter definitions
|
66
|
+
"""
|
55
67
|
filters = load(list[FFMpegFilter], "filters")
|
56
68
|
return {filter.name: filter for filter in filters}
|
57
69
|
|
@@ -99,6 +111,24 @@ def parse_options(tokens: list[str]) -> dict[str, list[str | None | bool]]:
|
|
99
111
|
def parse_stream_selector(
|
100
112
|
selector: str, mapping: Mapping[str, FilterableStream]
|
101
113
|
) -> FilterableStream:
|
114
|
+
"""
|
115
|
+
Parse a stream selector string and return the corresponding stream.
|
116
|
+
|
117
|
+
This function handles FFmpeg's stream selector syntax:
|
118
|
+
- Simple selectors: "[0]" (first input)
|
119
|
+
- Type selectors: "[0:v]" (first input, video stream)
|
120
|
+
- Index selectors: "[0:v:0]" (first input, first video stream)
|
121
|
+
|
122
|
+
Args:
|
123
|
+
selector: Stream selector string to parse
|
124
|
+
mapping: Dictionary of available streams
|
125
|
+
|
126
|
+
Returns:
|
127
|
+
The selected FilterableStream
|
128
|
+
|
129
|
+
Raises:
|
130
|
+
AssertionError: If the stream label is not found in the mapping
|
131
|
+
"""
|
102
132
|
selector = selector.strip("[]")
|
103
133
|
|
104
134
|
if ":" in selector:
|
@@ -126,19 +156,48 @@ def parse_stream_selector(
|
|
126
156
|
return stream
|
127
157
|
|
128
158
|
|
159
|
+
def _is_filename(token: str) -> bool:
|
160
|
+
"""
|
161
|
+
Check if a token is a filename.
|
162
|
+
|
163
|
+
Args:
|
164
|
+
token: The token to check
|
165
|
+
|
166
|
+
Returns:
|
167
|
+
True if the token is a filename, False otherwise
|
168
|
+
"""
|
169
|
+
# not start with - and has ext
|
170
|
+
return not token.startswith("-") and len(token.split(".")) > 1
|
171
|
+
|
172
|
+
|
129
173
|
def parse_output(
|
130
174
|
source: list[str],
|
131
175
|
in_streams: Mapping[str, FilterableStream],
|
132
176
|
ffmpeg_options: dict[str, FFMpegOption],
|
133
177
|
) -> list[OutputStream]:
|
178
|
+
"""
|
179
|
+
Parse output file specifications and their options.
|
180
|
+
|
181
|
+
This function processes the output portion of an FFmpeg command line,
|
182
|
+
handling output file paths, stream mapping, and output-specific options.
|
183
|
+
|
184
|
+
Args:
|
185
|
+
source: List of command-line tokens for output specifications
|
186
|
+
in_streams: Dictionary of available input streams
|
187
|
+
ffmpeg_options: Dictionary of valid FFmpeg options
|
188
|
+
|
189
|
+
Returns:
|
190
|
+
List of OutputStream objects representing the output specifications
|
191
|
+
"""
|
134
192
|
tokens = source.copy()
|
135
193
|
|
136
194
|
export: list[OutputStream] = []
|
137
|
-
|
138
195
|
buffer: list[str] = []
|
196
|
+
|
139
197
|
while tokens:
|
140
198
|
token = tokens.pop(0)
|
141
|
-
|
199
|
+
|
200
|
+
if not _is_filename(token):
|
142
201
|
buffer.append(token)
|
143
202
|
continue
|
144
203
|
|
@@ -161,8 +220,21 @@ def parse_output(
|
|
161
220
|
if isinstance(in_streams[k], AVStream)
|
162
221
|
]
|
163
222
|
|
164
|
-
|
165
|
-
|
223
|
+
parameters: dict[str, str | bool] = {}
|
224
|
+
|
225
|
+
for key, value in options.items():
|
226
|
+
key_base = key.split(":")[0]
|
227
|
+
if key_base in ffmpeg_options:
|
228
|
+
option = ffmpeg_options[key_base]
|
229
|
+
|
230
|
+
if option.is_output_option:
|
231
|
+
# just ignore not input options
|
232
|
+
if value[-1] is None:
|
233
|
+
parameters[key] = True
|
234
|
+
else:
|
235
|
+
parameters[key] = value[-1]
|
236
|
+
|
237
|
+
export.append(output(*inputs, filename=filename, extra_options=parameters))
|
166
238
|
buffer = []
|
167
239
|
|
168
240
|
return export
|
@@ -171,6 +243,19 @@ def parse_output(
|
|
171
243
|
def parse_input(
|
172
244
|
tokens: list[str], ffmpeg_options: dict[str, FFMpegOption]
|
173
245
|
) -> dict[str, FilterableStream]:
|
246
|
+
"""
|
247
|
+
Parse input file specifications and their options.
|
248
|
+
|
249
|
+
This function processes the input portion of an FFmpeg command line,
|
250
|
+
handling input file paths and input-specific options.
|
251
|
+
|
252
|
+
Args:
|
253
|
+
tokens: List of command-line tokens for input specifications
|
254
|
+
ffmpeg_options: Dictionary of valid FFmpeg options
|
255
|
+
|
256
|
+
Returns:
|
257
|
+
Dictionary mapping input indices to their FilterableStream objects
|
258
|
+
"""
|
174
259
|
output: list[AVStream] = []
|
175
260
|
|
176
261
|
while "-i" in tokens:
|
@@ -184,15 +269,15 @@ def parse_input(
|
|
184
269
|
parameters: dict[str, str | bool] = {}
|
185
270
|
|
186
271
|
for key, value in options.items():
|
187
|
-
|
188
|
-
|
272
|
+
if key in ffmpeg_options:
|
273
|
+
option = ffmpeg_options[key]
|
189
274
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
275
|
+
if option.is_input_option:
|
276
|
+
# just ignore not input options
|
277
|
+
if value[-1] is None:
|
278
|
+
parameters[key] = True
|
279
|
+
else:
|
280
|
+
parameters[key] = value[-1]
|
196
281
|
|
197
282
|
output.append(input(filename=filename, extra_options=parameters))
|
198
283
|
|
@@ -322,19 +407,42 @@ def parse_global(
|
|
322
407
|
parameters: dict[str, str | bool] = {}
|
323
408
|
|
324
409
|
for key, value in options.items():
|
325
|
-
|
326
|
-
|
410
|
+
if key in ffmpeg_options:
|
411
|
+
option = ffmpeg_options[key]
|
327
412
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
413
|
+
if option.is_global_option:
|
414
|
+
# Process only recognized global options
|
415
|
+
if value[-1] is None:
|
416
|
+
parameters[key] = True
|
417
|
+
else:
|
418
|
+
parameters[key] = value[-1]
|
334
419
|
return parameters, remaining_tokens
|
335
420
|
|
336
421
|
|
337
422
|
def parse(cli: str) -> Stream:
|
423
|
+
"""
|
424
|
+
Parse a complete FFmpeg command line into a Stream object.
|
425
|
+
|
426
|
+
This function takes a full FFmpeg command line string and converts it into
|
427
|
+
a Stream object representing the filter graph. It handles all components:
|
428
|
+
- Global options
|
429
|
+
- Input files and their options
|
430
|
+
- Filter complex
|
431
|
+
- Output files and their options
|
432
|
+
|
433
|
+
Args:
|
434
|
+
cli: Complete FFmpeg command line string
|
435
|
+
|
436
|
+
Returns:
|
437
|
+
Stream object representing the parsed command line
|
438
|
+
|
439
|
+
Example:
|
440
|
+
```python
|
441
|
+
stream = parse(
|
442
|
+
"ffmpeg -i input.mp4 -filter_complex '[0:v]scale=1280:720[v]' -map '[v]' output.mp4"
|
443
|
+
)
|
444
|
+
```
|
445
|
+
"""
|
338
446
|
# ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} ...
|
339
447
|
ffmpeg_options = get_options_dict()
|
340
448
|
ffmpeg_filters = get_filter_dict()
|
{typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: typed-ffmpeg-compatible
|
3
|
-
Version: 3.2.
|
3
|
+
Version: 3.2.3
|
4
4
|
Summary: Modern Python FFmpeg wrappers offer comprehensive support for complex filters, complete with detailed typing and documentation.
|
5
5
|
Author-email: lucemia <lucemia@gmail.com>
|
6
6
|
License-Expression: MIT
|
@@ -1,5 +1,5 @@
|
|
1
1
|
typed_ffmpeg/__init__.py,sha256=n1SZfENc9xhZ0eA3ZzkBNPuIY-Pt3-rOwB8-uUj5olU,1592
|
2
|
-
typed_ffmpeg/_version.py,sha256=
|
2
|
+
typed_ffmpeg/_version.py,sha256=P9n86yqDQj4uxDqvcIKGlJWsA9YZ7G1BSuEXNqVACeI,511
|
3
3
|
typed_ffmpeg/base.py,sha256=C5Tqbx2I0c-09D7aXKZoGkspu-lAAeAhuOns5zr3PXQ,6304
|
4
4
|
typed_ffmpeg/exceptions.py,sha256=D4SID6WOwkjVV8O8mAjrEDHWn-8BRDnK_jteaDof1SY,2474
|
5
5
|
typed_ffmpeg/filters.py,sha256=_lBpGZgPHK3KgGVrw-TCdQEsBRuEXVIgwggYNGd80MU,110076
|
@@ -13,7 +13,7 @@ typed_ffmpeg/common/cache.py,sha256=j0JvfX7jewLpdJWxgo7Pwze0BkUJdYGHX2uGR8BZ-9M,
|
|
13
13
|
typed_ffmpeg/common/schema.py,sha256=qM8yfMX9UU3EAQSNsTrr-SAmyqKx8eQCXTtu3RJWkEk,19673
|
14
14
|
typed_ffmpeg/common/serialize.py,sha256=dLim0DBP5CdJ1JiMV9xEmmh1XMSIhBOWs61EopAL15s,7719
|
15
15
|
typed_ffmpeg/compile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
-
typed_ffmpeg/compile/compile_cli.py,sha256
|
16
|
+
typed_ffmpeg/compile/compile_cli.py,sha256=--2j1QPPOB2pEQzqFM4VpINokbJilcegtRqTRF2_Jfg,31588
|
17
17
|
typed_ffmpeg/compile/compile_json.py,sha256=YCiTyfAnUVSbFr7BiQpmJYs13K5sa-xo77Iih33mb6I,992
|
18
18
|
typed_ffmpeg/compile/compile_python.py,sha256=oo4e8Ldwk0OkrZtHucfuGR5JDFF8xY8omNKPMDyUpQ8,11506
|
19
19
|
typed_ffmpeg/compile/context.py,sha256=macQ3HhEJ73j_WbWYtU9GCQCzcB_KQGAPimcuU-WOac,10946
|
@@ -50,9 +50,9 @@ typed_ffmpeg/utils/view.py,sha256=QCSlQoQkRBI-T0sWjiywGgM9DlKd8Te3CB2ZYX-pEVU,34
|
|
50
50
|
typed_ffmpeg/utils/lazy_eval/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
51
51
|
typed_ffmpeg/utils/lazy_eval/operator.py,sha256=QWybd-UH3VdDa8kgWkqAMi3WV0b0WF1d1JixQr6is2E,4136
|
52
52
|
typed_ffmpeg/utils/lazy_eval/schema.py,sha256=WSg-E3MS3itN1AT6Dq4Z9btnRHEReuN3o6zruXou7h4,9623
|
53
|
-
typed_ffmpeg_compatible-3.2.
|
54
|
-
typed_ffmpeg_compatible-3.2.
|
55
|
-
typed_ffmpeg_compatible-3.2.
|
56
|
-
typed_ffmpeg_compatible-3.2.
|
57
|
-
typed_ffmpeg_compatible-3.2.
|
58
|
-
typed_ffmpeg_compatible-3.2.
|
53
|
+
typed_ffmpeg_compatible-3.2.3.dist-info/licenses/LICENSE,sha256=8Aaya5i_09Cou2i3QMxTwz6uHGzi_fGA4uhkco07-A4,1066
|
54
|
+
typed_ffmpeg_compatible-3.2.3.dist-info/METADATA,sha256=HwRj91ZONWRkUUACimtXw8TNwhZveMe358-cYoBYaUU,8385
|
55
|
+
typed_ffmpeg_compatible-3.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
56
|
+
typed_ffmpeg_compatible-3.2.3.dist-info/entry_points.txt,sha256=kUQvZ27paV-07qtkIFV-emKsYtjFOTw9kknBRSXPs04,45
|
57
|
+
typed_ffmpeg_compatible-3.2.3.dist-info/top_level.txt,sha256=vuASJGVRQiNmhWY1pt0RXESWSNkknWXqWLIRAU7H_L4,13
|
58
|
+
typed_ffmpeg_compatible-3.2.3.dist-info/RECORD,,
|
File without changes
|
{typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/entry_points.txt
RENAMED
File without changes
|
{typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
{typed_ffmpeg_compatible-3.2.2.dist-info → typed_ffmpeg_compatible-3.2.3.dist-info}/top_level.txt
RENAMED
File without changes
|