typed-ffmpeg-compatible 3.2.4__py3-none-any.whl → 3.2.5__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 +37 -20
- typed_ffmpeg/compile/compile_python.py +10 -2
- typed_ffmpeg/streams/av.py +25 -2
- typed_ffmpeg/streams/subtitle.py +7 -0
- {typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.dist-info}/METADATA +1 -1
- {typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.dist-info}/RECORD +11 -10
- {typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.dist-info}/WHEEL +0 -0
- {typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.dist-info}/entry_points.txt +0 -0
- {typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.dist-info}/licenses/LICENSE +0 -0
- {typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.dist-info}/top_level.txt +0 -0
typed_ffmpeg/_version.py
CHANGED
@@ -38,6 +38,7 @@ from ..exceptions import FFMpegValueError
|
|
38
38
|
from ..schema import Default
|
39
39
|
from ..streams.audio import AudioStream
|
40
40
|
from ..streams.av import AVStream
|
41
|
+
from ..streams.subtitle import SubtitleStream
|
41
42
|
from ..streams.video import VideoStream
|
42
43
|
from ..utils.escaping import escape
|
43
44
|
from ..utils.lazy_eval.schema import LazyValue
|
@@ -140,20 +141,24 @@ def parse_stream_selector(
|
|
140
141
|
stream = mapping[stream_label]
|
141
142
|
|
142
143
|
if isinstance(stream, AVStream):
|
143
|
-
if
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
144
|
+
if ":" in selector:
|
145
|
+
if selector.count(":") == 1:
|
146
|
+
stream_label, stream_type = selector.split(":", 1)
|
147
|
+
stream_index = None
|
148
|
+
elif selector.count(":") == 2:
|
149
|
+
stream_label, stream_type, _stream_index = selector.split(":", 2)
|
150
|
+
stream_index = int(_stream_index)
|
151
|
+
|
152
|
+
match stream_type:
|
153
|
+
case "v":
|
154
|
+
return stream.video_stream(stream_index)
|
155
|
+
case "a":
|
156
|
+
return stream.audio_stream(stream_index)
|
157
|
+
case "s":
|
158
|
+
return stream.subtitle_stream(stream_index)
|
159
|
+
case _:
|
160
|
+
raise FFMpegValueError(f"Unknown stream type: {stream_type}")
|
161
|
+
return stream
|
157
162
|
|
158
163
|
|
159
164
|
def _is_filename(token: str) -> bool:
|
@@ -371,12 +376,17 @@ def parse_filter_complex(
|
|
371
376
|
for idx, (output_label, output_typing) in enumerate(
|
372
377
|
zip(output_labels, filter_node.output_typings)
|
373
378
|
):
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
379
|
+
match output_typing:
|
380
|
+
case StreamType.video:
|
381
|
+
stream_mapping[output_label] = VideoStream(
|
382
|
+
node=filter_node, index=idx
|
383
|
+
)
|
384
|
+
case StreamType.audio:
|
385
|
+
stream_mapping[output_label] = AudioStream(
|
386
|
+
node=filter_node, index=idx
|
387
|
+
)
|
388
|
+
case _:
|
389
|
+
raise FFMpegValueError(f"Unknown stream type: {output_typing}")
|
380
390
|
|
381
391
|
return stream_mapping
|
382
392
|
|
@@ -608,6 +618,7 @@ def get_stream_label(stream: Stream, context: DAGContext | None = None) -> str:
|
|
608
618
|
For input streams, labels follow FFmpeg's stream specifier syntax:
|
609
619
|
- Video streams: "0:v" (first input, video stream)
|
610
620
|
- Audio streams: "0:a" (first input, audio stream)
|
621
|
+
- Subtitle streams: "0:s" (first input, subtitle stream)
|
611
622
|
- AV streams: "0" (first input, all streams)
|
612
623
|
|
613
624
|
For filter outputs, labels use the filter's label:
|
@@ -649,6 +660,12 @@ def get_stream_label(stream: Stream, context: DAGContext | None = None) -> str:
|
|
649
660
|
f"{get_node_label(stream.node, context)}:a:{stream.index}"
|
650
661
|
)
|
651
662
|
return f"{get_node_label(stream.node, context)}:a"
|
663
|
+
case SubtitleStream():
|
664
|
+
if stream.index is not None:
|
665
|
+
return (
|
666
|
+
f"{get_node_label(stream.node, context)}:s:{stream.index}"
|
667
|
+
)
|
668
|
+
return f"{get_node_label(stream.node, context)}:s"
|
652
669
|
case _:
|
653
670
|
raise FFMpegValueError(
|
654
671
|
f"Unknown stream type: {stream.__class__.__name__}"
|
@@ -17,6 +17,7 @@ from ..dag.nodes import (
|
|
17
17
|
from ..dag.schema import Node, Stream
|
18
18
|
from ..streams.audio import AudioStream
|
19
19
|
from ..streams.av import AVStream
|
20
|
+
from ..streams.subtitle import SubtitleStream
|
20
21
|
from ..streams.video import VideoStream
|
21
22
|
from .context import DAGContext
|
22
23
|
from .validate import validate
|
@@ -107,12 +108,19 @@ def get_input_var_name(
|
|
107
108
|
return f"{get_output_var_name(stream.node, context)}[{stream.index}]"
|
108
109
|
else:
|
109
110
|
return f"{get_output_var_name(stream.node, context)}"
|
111
|
+
case SubtitleStream():
|
112
|
+
match stream.node:
|
113
|
+
case InputNode():
|
114
|
+
if stream.index is not None:
|
115
|
+
return f"{get_output_var_name(stream.node, context)}.subtitle_stream({stream.index})"
|
116
|
+
else:
|
117
|
+
return f"{get_output_var_name(stream.node, context)}.subtitle"
|
110
118
|
case OutputStream():
|
111
119
|
return f"{get_output_var_name(stream.node, context)}"
|
112
120
|
case GlobalStream():
|
113
121
|
return f"{get_output_var_name(stream.node, context)}"
|
114
|
-
|
115
|
-
|
122
|
+
|
123
|
+
raise ValueError(f"Unknown stream type: {type(stream)}") # pragma: no cover
|
116
124
|
|
117
125
|
|
118
126
|
def get_output_var_name(node: Node, context: DAGContext) -> str:
|
typed_ffmpeg/streams/av.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from ..dag.nodes import InputNode
|
2
2
|
from .audio import AudioStream
|
3
|
+
from .subtitle import SubtitleStream
|
3
4
|
from .video import VideoStream
|
4
5
|
|
5
6
|
|
@@ -30,7 +31,17 @@ class AVStream(AudioStream, VideoStream):
|
|
30
31
|
"""
|
31
32
|
return AudioStream(node=self.node, index=self.index)
|
32
33
|
|
33
|
-
|
34
|
+
@property
|
35
|
+
def subtitle(self) -> SubtitleStream:
|
36
|
+
"""
|
37
|
+
Get the subtitle stream from the input node.
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
SubtitleStream: The subtitle stream from the input node.
|
41
|
+
"""
|
42
|
+
return SubtitleStream(node=self.node, index=self.index)
|
43
|
+
|
44
|
+
def video_stream(self, index: int | None = None) -> VideoStream:
|
34
45
|
"""
|
35
46
|
Get the video stream from the input node with a specified index.
|
36
47
|
|
@@ -42,7 +53,7 @@ class AVStream(AudioStream, VideoStream):
|
|
42
53
|
"""
|
43
54
|
return VideoStream(node=self.node, index=index)
|
44
55
|
|
45
|
-
def audio_stream(self, index: int) -> AudioStream:
|
56
|
+
def audio_stream(self, index: int | None = None) -> AudioStream:
|
46
57
|
"""
|
47
58
|
Get the audio stream from the input node with a specified index.
|
48
59
|
|
@@ -53,3 +64,15 @@ class AVStream(AudioStream, VideoStream):
|
|
53
64
|
AudioStream: The audio stream from the input node.
|
54
65
|
"""
|
55
66
|
return AudioStream(node=self.node, index=index)
|
67
|
+
|
68
|
+
def subtitle_stream(self, index: int | None = None) -> SubtitleStream:
|
69
|
+
"""
|
70
|
+
Get the subtitle stream from the input node with a specified index.
|
71
|
+
|
72
|
+
Args:
|
73
|
+
index: The index of the subtitle stream.
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
SubtitleStream: The subtitle stream from the input node.
|
77
|
+
"""
|
78
|
+
return SubtitleStream(node=self.node, index=index)
|
{typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.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.5
|
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=VJzOHz1iq5b2MvgVxeYYraqogSncMB5aG1qIW2TvKks,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,9 +13,9 @@ 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=4XCkBC2WGP-P03XWVI3tgoBs--oQLvhuqyocSk8HhMw,32491
|
17
17
|
typed_ffmpeg/compile/compile_json.py,sha256=YCiTyfAnUVSbFr7BiQpmJYs13K5sa-xo77Iih33mb6I,992
|
18
|
-
typed_ffmpeg/compile/compile_python.py,sha256=
|
18
|
+
typed_ffmpeg/compile/compile_python.py,sha256=zxaG9DC0r8lO_cOV9HBN6cnxy3-wCZyvo3-4M47F84E,11914
|
19
19
|
typed_ffmpeg/compile/context.py,sha256=macQ3HhEJ73j_WbWYtU9GCQCzcB_KQGAPimcuU-WOac,10946
|
20
20
|
typed_ffmpeg/compile/validate.py,sha256=QsWksdvlRwWw6hnatFo-ABakms1qDXRbEmvMQGRLrD8,9579
|
21
21
|
typed_ffmpeg/dag/__init__.py,sha256=qAApSNqjbZ1DtUaV5bSku9RwG7MpMPa1HJO764cSBt4,849
|
@@ -37,8 +37,9 @@ typed_ffmpeg/ffprobe/schema.py,sha256=PBgBWYGO8wKnI0Lae9oCJ1Nprhv2ciPkdLrumzPVll
|
|
37
37
|
typed_ffmpeg/ffprobe/xml2json.py,sha256=1TSuxR7SYc-M_-JmE-1khHGbXCapgW0Oap9kzL0nwNg,2455
|
38
38
|
typed_ffmpeg/streams/__init__.py,sha256=Nt9uWpcVI1sQLl5Qt_kBCBcWOGZA1vczCQ0qvFbSko0,141
|
39
39
|
typed_ffmpeg/streams/audio.py,sha256=2oNRhb5UetWtlPG3NW73AjUZoFPl303yMv-6W1sGWt0,259054
|
40
|
-
typed_ffmpeg/streams/av.py,sha256=
|
40
|
+
typed_ffmpeg/streams/av.py,sha256=q7zqNyr44vBT7tiR2nKUGTf3g93HtNVA_WSwCiysmgI,2240
|
41
41
|
typed_ffmpeg/streams/channel_layout.py,sha256=hGagaoc1tnWS8K1yiITp4f_92qq5e7C_zB15bHOL0DI,1162
|
42
|
+
typed_ffmpeg/streams/subtitle.py,sha256=zhbRKUYH0C972Hurm4hK_dqLvT4Y6v_VNZFzQrkCm9A,141
|
42
43
|
typed_ffmpeg/streams/video.py,sha256=cQwHfew75YO_dbZjmpUYd-nXt1JHN0M7suFKKe5UH5s,453576
|
43
44
|
typed_ffmpeg/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
44
45
|
typed_ffmpeg/utils/escaping.py,sha256=m6CTEBwWZTFdtZHTHW-3pQCgkpdZb9f9ynoO-gsD7uM,2937
|
@@ -50,9 +51,9 @@ typed_ffmpeg/utils/view.py,sha256=QCSlQoQkRBI-T0sWjiywGgM9DlKd8Te3CB2ZYX-pEVU,34
|
|
50
51
|
typed_ffmpeg/utils/lazy_eval/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
51
52
|
typed_ffmpeg/utils/lazy_eval/operator.py,sha256=QWybd-UH3VdDa8kgWkqAMi3WV0b0WF1d1JixQr6is2E,4136
|
52
53
|
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.
|
54
|
+
typed_ffmpeg_compatible-3.2.5.dist-info/licenses/LICENSE,sha256=8Aaya5i_09Cou2i3QMxTwz6uHGzi_fGA4uhkco07-A4,1066
|
55
|
+
typed_ffmpeg_compatible-3.2.5.dist-info/METADATA,sha256=GSSr2eBSGWwgMrZZBx4wgAcRx6bas71nQjLxF8GVJPA,8385
|
56
|
+
typed_ffmpeg_compatible-3.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
57
|
+
typed_ffmpeg_compatible-3.2.5.dist-info/entry_points.txt,sha256=kUQvZ27paV-07qtkIFV-emKsYtjFOTw9kknBRSXPs04,45
|
58
|
+
typed_ffmpeg_compatible-3.2.5.dist-info/top_level.txt,sha256=vuASJGVRQiNmhWY1pt0RXESWSNkknWXqWLIRAU7H_L4,13
|
59
|
+
typed_ffmpeg_compatible-3.2.5.dist-info/RECORD,,
|
File without changes
|
{typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.dist-info}/entry_points.txt
RENAMED
File without changes
|
{typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
{typed_ffmpeg_compatible-3.2.4.dist-info → typed_ffmpeg_compatible-3.2.5.dist-info}/top_level.txt
RENAMED
File without changes
|