typed-ffmpeg-compatible 2.5.0__py3-none-any.whl → 2.6.1__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 +4 -0
- typed_ffmpeg/base.py +24 -5
- typed_ffmpeg/common/schema.py +25 -9
- typed_ffmpeg/common/serialize.py +9 -4
- typed_ffmpeg/dag/__init__.py +8 -1
- typed_ffmpeg/dag/context.py +7 -2
- typed_ffmpeg/dag/factory.py +29 -9
- typed_ffmpeg/dag/global_runnable/global_args.py +1 -2
- typed_ffmpeg/dag/global_runnable/runnable.py +9 -3
- typed_ffmpeg/dag/io/_input.py +3 -1
- typed_ffmpeg/dag/io/_output.py +3 -1
- typed_ffmpeg/dag/io/output_args.py +7 -4
- typed_ffmpeg/dag/nodes.py +59 -29
- typed_ffmpeg/dag/schema.py +3 -3
- typed_ffmpeg/dag/validate.py +26 -8
- typed_ffmpeg/exceptions.py +1 -1
- typed_ffmpeg/filters.py +304 -72
- typed_ffmpeg/info.py +167 -0
- typed_ffmpeg/probe.py +9 -2
- typed_ffmpeg/schema.py +0 -1
- typed_ffmpeg/streams/audio.py +697 -214
- typed_ffmpeg/streams/video.py +1400 -401
- typed_ffmpeg/utils/escaping.py +6 -5
- typed_ffmpeg/utils/run.py +1 -1
- typed_ffmpeg/utils/snapshot.py +10 -6
- typed_ffmpeg/utils/view.py +7 -2
- {typed_ffmpeg_compatible-2.5.0.dist-info → typed_ffmpeg_compatible-2.6.1.dist-info}/METADATA +1 -1
- typed_ffmpeg_compatible-2.6.1.dist-info/RECORD +46 -0
- typed_ffmpeg_compatible-2.5.0.dist-info/RECORD +0 -45
- {typed_ffmpeg_compatible-2.5.0.dist-info → typed_ffmpeg_compatible-2.6.1.dist-info}/LICENSE +0 -0
- {typed_ffmpeg_compatible-2.5.0.dist-info → typed_ffmpeg_compatible-2.6.1.dist-info}/WHEEL +0 -0
- {typed_ffmpeg_compatible-2.5.0.dist-info → typed_ffmpeg_compatible-2.6.1.dist-info}/entry_points.txt +0 -0
typed_ffmpeg/info.py
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
import logging
|
2
|
+
import subprocess
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from enum import Flag, auto
|
5
|
+
|
6
|
+
from .exceptions import FFMpegExecuteError
|
7
|
+
from .utils.run import command_line
|
8
|
+
|
9
|
+
logger = logging.getLogger(__name__)
|
10
|
+
|
11
|
+
|
12
|
+
class CodecFlags(Flag):
|
13
|
+
video = auto()
|
14
|
+
audio = auto()
|
15
|
+
subtitle = auto()
|
16
|
+
frame_level_multithreading = auto()
|
17
|
+
slice_level_multithreading = auto()
|
18
|
+
experimental = auto()
|
19
|
+
draw_horiz_band = auto()
|
20
|
+
direct_rendering_method_1 = auto()
|
21
|
+
|
22
|
+
|
23
|
+
@dataclass(frozen=True)
|
24
|
+
class Codec:
|
25
|
+
name: str
|
26
|
+
flags: CodecFlags
|
27
|
+
description: str
|
28
|
+
|
29
|
+
|
30
|
+
def parse_codec_flags(flags: str) -> CodecFlags:
|
31
|
+
flags_enum = CodecFlags(0)
|
32
|
+
if flags[0] == "V":
|
33
|
+
flags_enum |= CodecFlags.video
|
34
|
+
if flags[0] == "A":
|
35
|
+
flags_enum |= CodecFlags.audio
|
36
|
+
if flags[0] == "S":
|
37
|
+
flags_enum |= CodecFlags.subtitle
|
38
|
+
if flags[1] == "F":
|
39
|
+
flags_enum |= CodecFlags.frame_level_multithreading
|
40
|
+
if flags[2] == "S":
|
41
|
+
flags_enum |= CodecFlags.slice_level_multithreading
|
42
|
+
if flags[3] == "X":
|
43
|
+
flags_enum |= CodecFlags.experimental
|
44
|
+
if flags[4] == "B":
|
45
|
+
flags_enum |= CodecFlags.draw_horiz_band
|
46
|
+
if flags[5] == "D":
|
47
|
+
flags_enum |= CodecFlags.direct_rendering_method_1
|
48
|
+
return flags_enum
|
49
|
+
|
50
|
+
|
51
|
+
def get_codecs() -> tuple[Codec, ...]:
|
52
|
+
args = ["ffmpeg", "-hide_banner", "-codecs"]
|
53
|
+
logger.info("Running ffmpeg command: %s", command_line(args))
|
54
|
+
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
55
|
+
out, err = p.communicate()
|
56
|
+
|
57
|
+
retcode = p.poll()
|
58
|
+
if p.returncode != 0:
|
59
|
+
raise FFMpegExecuteError(
|
60
|
+
retcode=retcode, cmd=command_line(args), stdout=out, stderr=err
|
61
|
+
)
|
62
|
+
|
63
|
+
codecs = out.decode("utf-8")
|
64
|
+
codecs_lines = codecs.strip().split("\n")
|
65
|
+
# Skip header lines until we find the separator
|
66
|
+
for i, line in enumerate(codecs_lines):
|
67
|
+
if line.startswith(" ------"):
|
68
|
+
codecs_lines = codecs_lines[i + 1 :]
|
69
|
+
break
|
70
|
+
return tuple(
|
71
|
+
Codec(
|
72
|
+
name=parts[1],
|
73
|
+
flags=parse_codec_flags(parts[0]),
|
74
|
+
description=parts[2],
|
75
|
+
)
|
76
|
+
for line in codecs_lines
|
77
|
+
for parts in [line.split(None, 3)]
|
78
|
+
)
|
79
|
+
|
80
|
+
|
81
|
+
class CoderFlags(Flag):
|
82
|
+
video = auto()
|
83
|
+
audio = auto()
|
84
|
+
subtitle = auto()
|
85
|
+
frame_level_multithreading = auto()
|
86
|
+
slice_level_multithreading = auto()
|
87
|
+
experimental = auto()
|
88
|
+
draw_horiz_band = auto()
|
89
|
+
direct_rendering_method_1 = auto()
|
90
|
+
|
91
|
+
|
92
|
+
def parse_coder_flags(flags: str) -> CoderFlags:
|
93
|
+
flags_enum = CoderFlags(0)
|
94
|
+
if flags[0] == "V":
|
95
|
+
flags_enum |= CoderFlags.video
|
96
|
+
if flags[0] == "A":
|
97
|
+
flags_enum |= CoderFlags.audio
|
98
|
+
if flags[0] == "S":
|
99
|
+
flags_enum |= CoderFlags.subtitle
|
100
|
+
if flags[1] == "F":
|
101
|
+
flags_enum |= CoderFlags.frame_level_multithreading
|
102
|
+
if flags[2] == "S":
|
103
|
+
flags_enum |= CoderFlags.slice_level_multithreading
|
104
|
+
if flags[3] == "X":
|
105
|
+
flags_enum |= CoderFlags.experimental
|
106
|
+
if flags[4] == "B":
|
107
|
+
flags_enum |= CoderFlags.draw_horiz_band
|
108
|
+
if flags[5] == "D":
|
109
|
+
flags_enum |= CoderFlags.direct_rendering_method_1
|
110
|
+
return flags_enum
|
111
|
+
|
112
|
+
|
113
|
+
@dataclass
|
114
|
+
class Coder:
|
115
|
+
name: str
|
116
|
+
flags: CoderFlags
|
117
|
+
description: str
|
118
|
+
|
119
|
+
|
120
|
+
def get_coders(codes: str) -> tuple[Coder, ...]:
|
121
|
+
codecs_lines = codes.strip().split("\n")
|
122
|
+
# Skip header lines until we find the separator
|
123
|
+
for i, line in enumerate(codecs_lines):
|
124
|
+
if line.startswith(" ------"):
|
125
|
+
codecs_lines = codecs_lines[i + 1 :]
|
126
|
+
break
|
127
|
+
return tuple(
|
128
|
+
Coder(
|
129
|
+
name=parts[1],
|
130
|
+
flags=parse_coder_flags(parts[0]),
|
131
|
+
description=parts[2],
|
132
|
+
)
|
133
|
+
for line in codecs_lines
|
134
|
+
for parts in [line.split(None, 3)]
|
135
|
+
)
|
136
|
+
|
137
|
+
|
138
|
+
def get_decoders() -> tuple[Coder, ...]:
|
139
|
+
args = ["ffmpeg", "-hide_banner", "-decoders"]
|
140
|
+
logger.info("Running ffmpeg command: %s", command_line(args))
|
141
|
+
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
142
|
+
out, err = p.communicate()
|
143
|
+
|
144
|
+
retcode = p.poll()
|
145
|
+
if p.returncode != 0:
|
146
|
+
raise FFMpegExecuteError(
|
147
|
+
retcode=retcode, cmd=command_line(args), stdout=out, stderr=err
|
148
|
+
)
|
149
|
+
|
150
|
+
decoders = out.decode("utf-8")
|
151
|
+
return get_coders(decoders)
|
152
|
+
|
153
|
+
|
154
|
+
def get_encoders() -> tuple[Coder, ...]:
|
155
|
+
args = ["ffmpeg", "-hide_banner", "-encoders"]
|
156
|
+
logger.info("Running ffmpeg command: %s", command_line(args))
|
157
|
+
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
158
|
+
out, err = p.communicate()
|
159
|
+
|
160
|
+
retcode = p.poll()
|
161
|
+
if p.returncode != 0:
|
162
|
+
raise FFMpegExecuteError(
|
163
|
+
retcode=retcode, cmd=command_line(args), stdout=out, stderr=err
|
164
|
+
)
|
165
|
+
|
166
|
+
encoders = out.decode("utf-8")
|
167
|
+
return get_coders(encoders)
|
typed_ffmpeg/probe.py
CHANGED
@@ -11,7 +11,12 @@ from .utils.run import command_line
|
|
11
11
|
logger = logging.getLogger(__name__)
|
12
12
|
|
13
13
|
|
14
|
-
def probe(
|
14
|
+
def probe(
|
15
|
+
filename: str | Path,
|
16
|
+
cmd: str = "ffprobe",
|
17
|
+
timeout: int | None = None,
|
18
|
+
**kwargs: Any,
|
19
|
+
) -> dict[str, Any]:
|
15
20
|
"""
|
16
21
|
Run ffprobe on the given file and return a JSON representation of the output
|
17
22
|
|
@@ -38,6 +43,8 @@ def probe(filename: str | Path, cmd: str = "ffprobe", timeout: int | None = None
|
|
38
43
|
|
39
44
|
retcode = p.poll()
|
40
45
|
if p.returncode != 0:
|
41
|
-
raise FFMpegExecuteError(
|
46
|
+
raise FFMpegExecuteError(
|
47
|
+
retcode=retcode, cmd=command_line(args), stdout=out, stderr=err
|
48
|
+
)
|
42
49
|
|
43
50
|
return json.loads(out.decode("utf-8"))
|