auto-editor 24.9.1__py3-none-any.whl → 24.13.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.
- ae-ffmpeg/ae_ffmpeg/__init__.py +1 -1
- auto_editor/__init__.py +2 -2
- auto_editor/edit.py +2 -2
- auto_editor/ffwrapper.py +23 -50
- auto_editor/formats/fcp11.py +6 -6
- auto_editor/formats/fcp7.py +1 -2
- auto_editor/formats/json.py +8 -8
- auto_editor/output.py +13 -6
- auto_editor/render/video.py +0 -1
- auto_editor/subcommands/desc.py +2 -4
- auto_editor/subcommands/info.py +24 -19
- auto_editor/subcommands/levels.py +1 -1
- auto_editor/subcommands/repl.py +1 -1
- auto_editor/subcommands/subdump.py +14 -49
- auto_editor/subcommands/test.py +7 -6
- auto_editor/wavfile.py +3 -3
- {auto_editor-24.9.1.dist-info → auto_editor-24.13.1.dist-info}/METADATA +3 -3
- {auto_editor-24.9.1.dist-info → auto_editor-24.13.1.dist-info}/RECORD +22 -22
- {auto_editor-24.9.1.dist-info → auto_editor-24.13.1.dist-info}/WHEEL +1 -1
- {auto_editor-24.9.1.dist-info → auto_editor-24.13.1.dist-info}/LICENSE +0 -0
- {auto_editor-24.9.1.dist-info → auto_editor-24.13.1.dist-info}/entry_points.txt +0 -0
- {auto_editor-24.9.1.dist-info → auto_editor-24.13.1.dist-info}/top_level.txt +0 -0
ae-ffmpeg/ae_ffmpeg/__init__.py
CHANGED
auto_editor/__init__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
__version__ = "24.
|
2
|
-
version = "
|
1
|
+
__version__ = "24.13.1"
|
2
|
+
version = "24w13a"
|
auto_editor/edit.py
CHANGED
@@ -177,11 +177,11 @@ def edit_media(
|
|
177
177
|
elif path_ext == ".json":
|
178
178
|
from auto_editor.formats.json import read_json
|
179
179
|
|
180
|
-
tl = read_json(paths[0],
|
180
|
+
tl = read_json(paths[0], log)
|
181
181
|
sources = [] if tl.src is None else [tl.src]
|
182
182
|
src = tl.src
|
183
183
|
else:
|
184
|
-
sources = [initFileInfo(path,
|
184
|
+
sources = [initFileInfo(path, log) for path in paths]
|
185
185
|
src = None if not sources else sources[0]
|
186
186
|
|
187
187
|
del paths
|
auto_editor/ffwrapper.py
CHANGED
@@ -135,10 +135,10 @@ class VideoStream:
|
|
135
135
|
sar: Fraction
|
136
136
|
time_base: Fraction | None
|
137
137
|
pix_fmt: str | None
|
138
|
-
color_range:
|
139
|
-
color_space:
|
140
|
-
color_primaries:
|
141
|
-
color_transfer:
|
138
|
+
color_range: int
|
139
|
+
color_space: int
|
140
|
+
color_primaries: int
|
141
|
+
color_transfer: int
|
142
142
|
bitrate: int
|
143
143
|
lang: str | None
|
144
144
|
|
@@ -189,7 +189,7 @@ class FileInfo:
|
|
189
189
|
return f"@{self.path.name}"
|
190
190
|
|
191
191
|
|
192
|
-
def initFileInfo(path: str,
|
192
|
+
def initFileInfo(path: str, log: Log) -> FileInfo:
|
193
193
|
import av
|
194
194
|
|
195
195
|
av.logging.set_level(av.logging.PANIC)
|
@@ -203,14 +203,11 @@ def initFileInfo(path: str, ffmpeg: FFmpeg, log: Log) -> FileInfo:
|
|
203
203
|
audios: tuple[AudioStream, ...] = ()
|
204
204
|
subtitles: tuple[SubtitleStream, ...] = ()
|
205
205
|
|
206
|
-
|
207
|
-
_ext = os.path.splitext(ffmpeg.path)[1]
|
208
|
-
ffprobe = os.path.join(_dir, f"ffprobe{_ext}")
|
209
|
-
|
210
|
-
for i, v in enumerate(cont.streams.video):
|
211
|
-
vdur = 0.0
|
206
|
+
for v in cont.streams.video:
|
212
207
|
if v.duration is not None and v.time_base is not None:
|
213
208
|
vdur = float(v.duration * v.time_base)
|
209
|
+
else:
|
210
|
+
vdur = 0.0
|
214
211
|
|
215
212
|
fps = v.average_rate
|
216
213
|
if (fps is None or fps < 1) and v.name in ("png", "mjpeg", "webp"):
|
@@ -218,36 +215,11 @@ def initFileInfo(path: str, ffmpeg: FFmpeg, log: Log) -> FileInfo:
|
|
218
215
|
if fps is None or fps == 0:
|
219
216
|
fps = Fraction(30)
|
220
217
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
"-v",
|
227
|
-
"error",
|
228
|
-
"-select_streams",
|
229
|
-
f"v:{i}",
|
230
|
-
"-show_entries",
|
231
|
-
"stream=sample_aspect_ratio:stream=color_range:stream=color_space:stream=color_primaries:stream=color_transfer",
|
232
|
-
"-of",
|
233
|
-
"default=noprint_wrappers=1:nokey=1",
|
234
|
-
path,
|
235
|
-
]
|
236
|
-
)
|
237
|
-
_sar, c_range, c_space, c_primary, c_transfer = _raw.strip().split("\n")
|
238
|
-
except Exception:
|
239
|
-
log.debug("Unexpected ffprobe shape")
|
240
|
-
|
241
|
-
if v.sample_aspect_ratio is None:
|
242
|
-
if _sar is None:
|
243
|
-
sar = Fraction(1)
|
244
|
-
else:
|
245
|
-
try:
|
246
|
-
sar = Fraction(_sar.replace(":", "/"))
|
247
|
-
except Exception:
|
248
|
-
sar = Fraction(1)
|
249
|
-
else:
|
250
|
-
sar = v.sample_aspect_ratio
|
218
|
+
sar = Fraction(1) if v.sample_aspect_ratio is None else v.sample_aspect_ratio
|
219
|
+
cc = v.codec_context
|
220
|
+
|
221
|
+
if v.name is None:
|
222
|
+
log.error(f"Can't detect codec for video stream {v}")
|
251
223
|
|
252
224
|
videos += (
|
253
225
|
VideoStream(
|
@@ -258,11 +230,11 @@ def initFileInfo(path: str, ffmpeg: FFmpeg, log: Log) -> FileInfo:
|
|
258
230
|
vdur,
|
259
231
|
sar,
|
260
232
|
v.time_base,
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
233
|
+
cc.pix_fmt,
|
234
|
+
cc.color_range,
|
235
|
+
cc.colorspace,
|
236
|
+
cc.color_primaries,
|
237
|
+
cc.color_trc,
|
266
238
|
0 if v.bit_rate is None else v.bit_rate,
|
267
239
|
v.language,
|
268
240
|
),
|
@@ -273,13 +245,14 @@ def initFileInfo(path: str, ffmpeg: FFmpeg, log: Log) -> FileInfo:
|
|
273
245
|
if a.duration is not None and a.time_base is not None:
|
274
246
|
adur = float(a.duration * a.time_base)
|
275
247
|
|
248
|
+
a_cc = a.codec_context
|
276
249
|
audios += (
|
277
250
|
AudioStream(
|
278
|
-
|
279
|
-
0 if
|
280
|
-
|
251
|
+
a_cc.name,
|
252
|
+
0 if a_cc.sample_rate is None else a_cc.sample_rate,
|
253
|
+
a_cc.channels,
|
281
254
|
adur,
|
282
|
-
0 if
|
255
|
+
0 if a_cc.bit_rate is None else a_cc.bit_rate,
|
283
256
|
a.language,
|
284
257
|
),
|
285
258
|
)
|
auto_editor/formats/fcp11.py
CHANGED
@@ -32,13 +32,13 @@ def get_colorspace(src: FileInfo) -> str:
|
|
32
32
|
s = src.videos[0]
|
33
33
|
if s.pix_fmt == "rgb24":
|
34
34
|
return "sRGB IEC61966-2.1"
|
35
|
-
if s.color_space == "
|
36
|
-
return "6-1-6 (Rec. 601 NTSC)"
|
37
|
-
if s.color_space == "bt470bg":
|
35
|
+
if s.color_space == 5: # "bt470bg"
|
38
36
|
return "5-1-6 (Rec. 601 PAL)"
|
39
|
-
if s.
|
37
|
+
if s.color_space == 6: # "smpte170m"
|
38
|
+
return "6-1-6 (Rec. 601 NTSC)"
|
39
|
+
if s.color_primaries == 9: # "bt2020"
|
40
40
|
# See: https://video.stackexchange.com/questions/22059/how-to-identify-hdr-video
|
41
|
-
if s.color_transfer in ("arib-std-b67"
|
41
|
+
if s.color_transfer in (16, 18): # "smpte2084" "arib-std-b67"
|
42
42
|
return "9-18-9 (Rec. 2020 HLG)"
|
43
43
|
return "9-1-9 (Rec. 2020)"
|
44
44
|
|
@@ -79,7 +79,7 @@ def fcp11_write_xml(
|
|
79
79
|
ffmpeg.run(
|
80
80
|
["-i", f"{src.path.resolve()}", "-map", f"0:a:{i}", f"{newtrack}"]
|
81
81
|
)
|
82
|
-
all_srcs.append(initFileInfo(f"{newtrack}",
|
82
|
+
all_srcs.append(initFileInfo(f"{newtrack}", log))
|
83
83
|
all_refs.append(f"r{(i + 1) * 2}")
|
84
84
|
|
85
85
|
fcpxml = Element("fcpxml", version="1.10" if flavor == "resolve" else "1.11")
|
auto_editor/formats/fcp7.py
CHANGED
@@ -281,7 +281,6 @@ def fcp7_read_xml(path: str, ffmpeg: FFmpeg, log: Log) -> v3:
|
|
281
281
|
if "pathurl" in fileobj:
|
282
282
|
sources[file_id] = initFileInfo(
|
283
283
|
uri_to_path(fileobj["pathurl"]),
|
284
|
-
ffmpeg,
|
285
284
|
log,
|
286
285
|
)
|
287
286
|
else:
|
@@ -315,7 +314,7 @@ def fcp7_read_xml(path: str, ffmpeg: FFmpeg, log: Log) -> v3:
|
|
315
314
|
if file_id not in sources:
|
316
315
|
fileobj = valid.parse(clipitem["file"], {"pathurl": str})
|
317
316
|
sources[file_id] = initFileInfo(
|
318
|
-
uri_to_path(fileobj["pathurl"]),
|
317
|
+
uri_to_path(fileobj["pathurl"]), log
|
319
318
|
)
|
320
319
|
|
321
320
|
if "filter" in clipitem:
|
auto_editor/formats/json.py
CHANGED
@@ -6,7 +6,7 @@ from difflib import get_close_matches
|
|
6
6
|
from fractions import Fraction
|
7
7
|
from typing import Any
|
8
8
|
|
9
|
-
from auto_editor.ffwrapper import
|
9
|
+
from auto_editor.ffwrapper import FileInfo, initFileInfo
|
10
10
|
from auto_editor.lang.json import Lexer, Parser, dump
|
11
11
|
from auto_editor.lib.err import MyError
|
12
12
|
from auto_editor.timeline import (
|
@@ -42,7 +42,7 @@ def check_file(path: str, log: Log) -> None:
|
|
42
42
|
log.error(f"Could not locate media file: '{path}'")
|
43
43
|
|
44
44
|
|
45
|
-
def read_v3(tl: Any,
|
45
|
+
def read_v3(tl: Any, log: Log) -> v3:
|
46
46
|
check_attrs(
|
47
47
|
tl,
|
48
48
|
log,
|
@@ -59,7 +59,7 @@ def read_v3(tl: Any, ffmpeg: FFmpeg, log: Log) -> v3:
|
|
59
59
|
def make_src(v: str) -> FileInfo:
|
60
60
|
if v in srcs:
|
61
61
|
return srcs[v]
|
62
|
-
temp = initFileInfo(v,
|
62
|
+
temp = initFileInfo(v, log)
|
63
63
|
srcs[v] = temp
|
64
64
|
return temp
|
65
65
|
|
@@ -158,7 +158,7 @@ def read_v3(tl: Any, ffmpeg: FFmpeg, log: Log) -> v3:
|
|
158
158
|
return v3(src, tb, sr, res, bg, v, a, v1=None)
|
159
159
|
|
160
160
|
|
161
|
-
def read_v1(tl: Any,
|
161
|
+
def read_v1(tl: Any, log: Log) -> v3:
|
162
162
|
from auto_editor.make_layers import clipify
|
163
163
|
|
164
164
|
check_attrs(tl, log, "source", "chunks")
|
@@ -168,7 +168,7 @@ def read_v1(tl: Any, ffmpeg: FFmpeg, log: Log) -> v3:
|
|
168
168
|
|
169
169
|
check_file(path, log)
|
170
170
|
|
171
|
-
src = initFileInfo(path,
|
171
|
+
src = initFileInfo(path, log)
|
172
172
|
|
173
173
|
vtl: VSpace = []
|
174
174
|
atl: ASpace = [[] for _ in range(len(src.audios))]
|
@@ -194,7 +194,7 @@ def read_v1(tl: Any, ffmpeg: FFmpeg, log: Log) -> v3:
|
|
194
194
|
)
|
195
195
|
|
196
196
|
|
197
|
-
def read_json(path: str,
|
197
|
+
def read_json(path: str, log: Log) -> v3:
|
198
198
|
with open(path, encoding="utf-8", errors="ignore") as f:
|
199
199
|
try:
|
200
200
|
tl = Parser(Lexer(path, f)).expr()
|
@@ -206,9 +206,9 @@ def read_json(path: str, ffmpeg: FFmpeg, log: Log) -> v3:
|
|
206
206
|
ver = tl["version"]
|
207
207
|
|
208
208
|
if ver == "3":
|
209
|
-
return read_v3(tl,
|
209
|
+
return read_v3(tl, log)
|
210
210
|
if ver == "1":
|
211
|
-
return read_v1(tl,
|
211
|
+
return read_v1(tl, log)
|
212
212
|
if type(ver) is not str:
|
213
213
|
log.error("version needs to be a string")
|
214
214
|
log.error(f"Importing version {ver} timelines is not supported.")
|
auto_editor/output.py
CHANGED
@@ -182,12 +182,19 @@ def mux_quality_media(
|
|
182
182
|
cmd += _ffset("-c:a", args.audio_codec) + _ffset("-b:a", args.audio_bitrate)
|
183
183
|
|
184
184
|
if same_container and v_tracks > 0:
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
185
|
+
color_range = src.videos[0].color_range
|
186
|
+
colorspace = src.videos[0].color_space
|
187
|
+
color_prim = src.videos[0].color_primaries
|
188
|
+
color_trc = src.videos[0].color_transfer
|
189
|
+
|
190
|
+
if color_range == 1 or color_range == 2:
|
191
|
+
cmd.extend(["-color_range", f"{color_range}"])
|
192
|
+
if colorspace in (0, 1) or (colorspace >= 3 and colorspace < 16):
|
193
|
+
cmd.extend(["-colorspace", f"{colorspace}"])
|
194
|
+
if color_prim in (0, 1) or (color_prim >= 4 and color_prim < 17):
|
195
|
+
cmd.extend(["-color_primaries", f"{color_prim}"])
|
196
|
+
if color_trc == 1 or (color_trc >= 4 and color_trc < 22):
|
197
|
+
cmd.extend(["-color_trc", f"{color_trc}"])
|
191
198
|
|
192
199
|
if args.extras is not None:
|
193
200
|
cmd.extend(args.extras.split(" "))
|
auto_editor/render/video.py
CHANGED
@@ -97,7 +97,6 @@ def make_image_cache(tl: v3) -> dict[tuple[FileInfo, int], np.ndarray]:
|
|
97
97
|
for obj in clip:
|
98
98
|
if isinstance(obj, TlImage) and obj.src not in img_cache:
|
99
99
|
with av.open(obj.src.path) as cn:
|
100
|
-
assert isinstance(cn, av.InputContainer)
|
101
100
|
my_stream = cn.streams.video[0]
|
102
101
|
for frame in cn.decode(my_stream):
|
103
102
|
if obj.width != 0:
|
auto_editor/subcommands/desc.py
CHANGED
@@ -3,28 +3,26 @@ from __future__ import annotations
|
|
3
3
|
import sys
|
4
4
|
from dataclasses import dataclass, field
|
5
5
|
|
6
|
-
from auto_editor.ffwrapper import
|
6
|
+
from auto_editor.ffwrapper import initFileInfo
|
7
7
|
from auto_editor.utils.log import Log
|
8
8
|
from auto_editor.vanparse import ArgumentParser
|
9
9
|
|
10
10
|
|
11
11
|
@dataclass(slots=True)
|
12
12
|
class DescArgs:
|
13
|
-
ffmpeg_location: str | None = None
|
14
13
|
help: bool = False
|
15
14
|
input: list[str] = field(default_factory=list)
|
16
15
|
|
17
16
|
|
18
17
|
def desc_options(parser: ArgumentParser) -> ArgumentParser:
|
19
18
|
parser.add_required("input", nargs="*")
|
20
|
-
parser.add_argument("--ffmpeg-location", help="Point to your custom ffmpeg file")
|
21
19
|
return parser
|
22
20
|
|
23
21
|
|
24
22
|
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
25
23
|
args = desc_options(ArgumentParser("desc")).parse_args(DescArgs, sys_args)
|
26
24
|
for path in args.input:
|
27
|
-
src = initFileInfo(path,
|
25
|
+
src = initFileInfo(path, Log())
|
28
26
|
if src.description is not None:
|
29
27
|
sys.stdout.write(f"\n{src.description}\n\n")
|
30
28
|
else:
|
auto_editor/subcommands/info.py
CHANGED
@@ -5,7 +5,7 @@ import sys
|
|
5
5
|
from dataclasses import dataclass, field
|
6
6
|
from typing import Any, Literal, TypedDict
|
7
7
|
|
8
|
-
from auto_editor.ffwrapper import
|
8
|
+
from auto_editor.ffwrapper import initFileInfo
|
9
9
|
from auto_editor.lang.json import dump
|
10
10
|
from auto_editor.timeline import v3
|
11
11
|
from auto_editor.utils.func import aspect_ratio
|
@@ -16,8 +16,6 @@ from auto_editor.vanparse import ArgumentParser
|
|
16
16
|
@dataclass(slots=True)
|
17
17
|
class InfoArgs:
|
18
18
|
json: bool = False
|
19
|
-
ffmpeg_location: str | None = None
|
20
|
-
my_ffmpeg: bool = False
|
21
19
|
help: bool = False
|
22
20
|
input: list[str] = field(default_factory=list)
|
23
21
|
|
@@ -25,12 +23,6 @@ class InfoArgs:
|
|
25
23
|
def info_options(parser: ArgumentParser) -> ArgumentParser:
|
26
24
|
parser.add_required("input", nargs="*")
|
27
25
|
parser.add_argument("--json", flag=True, help="Export info in JSON format")
|
28
|
-
parser.add_argument("--ffmpeg-location", help="Point to your custom ffmpeg file")
|
29
|
-
parser.add_argument(
|
30
|
-
"--my-ffmpeg",
|
31
|
-
flag=True,
|
32
|
-
help="Use the ffmpeg on your PATH instead of the one packaged",
|
33
|
-
)
|
34
26
|
return parser
|
35
27
|
|
36
28
|
|
@@ -42,10 +34,10 @@ class VideoJson(TypedDict):
|
|
42
34
|
pixel_aspect_ratio: str
|
43
35
|
duration: float
|
44
36
|
pix_fmt: str | None
|
45
|
-
color_range:
|
46
|
-
color_space:
|
47
|
-
color_primaries:
|
48
|
-
color_transfer:
|
37
|
+
color_range: int
|
38
|
+
color_space: int
|
39
|
+
color_primaries: int
|
40
|
+
color_transfer: int
|
49
41
|
timebase: str
|
50
42
|
bitrate: int
|
51
43
|
lang: str | None
|
@@ -83,7 +75,6 @@ class MediaJson(TypedDict, total=False):
|
|
83
75
|
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
84
76
|
args = info_options(ArgumentParser("info")).parse_args(InfoArgs, sys_args)
|
85
77
|
|
86
|
-
ffmpeg = FFmpeg(args.ffmpeg_location, args.my_ffmpeg)
|
87
78
|
log = Log(quiet=not args.json)
|
88
79
|
|
89
80
|
file_info: dict[str, MediaJson] = {}
|
@@ -96,7 +87,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
96
87
|
if ext == ".json":
|
97
88
|
from auto_editor.formats.json import read_json
|
98
89
|
|
99
|
-
tl = read_json(file,
|
90
|
+
tl = read_json(file, log)
|
100
91
|
file_info[file] = {"type": "timeline"}
|
101
92
|
file_info[file]["version"] = "v3" if isinstance(tl, v3) else "v1"
|
102
93
|
|
@@ -109,7 +100,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
109
100
|
file_info[file] = {"type": "timeline"}
|
110
101
|
continue
|
111
102
|
|
112
|
-
src = initFileInfo(file,
|
103
|
+
src = initFileInfo(file, log)
|
113
104
|
|
114
105
|
if len(src.videos) + len(src.audios) + len(src.subtitles) == 0:
|
115
106
|
file_info[file] = {"type": "unknown"}
|
@@ -177,13 +168,27 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
177
168
|
text += f" - track {s}:\n"
|
178
169
|
for key, value in stream.items():
|
179
170
|
if not is_null(key, value):
|
180
|
-
key = key.replace("_", " ")
|
181
171
|
if isinstance(value, list):
|
182
172
|
sep = "x" if key == "resolution" else ":"
|
183
|
-
|
184
173
|
value = sep.join(f"{x}" for x in value)
|
185
174
|
|
186
|
-
|
175
|
+
if key in (
|
176
|
+
"color_range",
|
177
|
+
"color_space",
|
178
|
+
"color_transfer",
|
179
|
+
"color_primaries",
|
180
|
+
):
|
181
|
+
if key == "color_range":
|
182
|
+
if value == 1:
|
183
|
+
text += " - color range: 1 (tv)\n"
|
184
|
+
elif value == 2:
|
185
|
+
text += " - color range: 2 (pc)\n"
|
186
|
+
elif value == 1:
|
187
|
+
text += f" - {key.replace('_', ' ')}: 1 (bt709)\n"
|
188
|
+
elif value != 2:
|
189
|
+
text += f" - {key.replace('_', ' ')}: {value}\n"
|
190
|
+
else:
|
191
|
+
text += f" - {key.replace('_', ' ')}: {value}\n"
|
187
192
|
return text
|
188
193
|
|
189
194
|
text = ""
|
@@ -78,7 +78,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
78
78
|
temp = setup_tempdir(None, Log())
|
79
79
|
log = Log(quiet=True, temp=temp)
|
80
80
|
|
81
|
-
sources = [initFileInfo(path,
|
81
|
+
sources = [initFileInfo(path, log) for path in args.input]
|
82
82
|
if len(sources) < 1:
|
83
83
|
log.error("levels needs at least one input file")
|
84
84
|
|
auto_editor/subcommands/repl.py
CHANGED
@@ -70,7 +70,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
70
70
|
log = Log(quiet=True, temp=temp)
|
71
71
|
ffmpeg = FFmpeg(args.ffmpeg_location, args.my_ffmpeg, False)
|
72
72
|
strict = len(args.input) < 2
|
73
|
-
sources = [initFileInfo(path,
|
73
|
+
sources = [initFileInfo(path, log) for path in args.input]
|
74
74
|
src = sources[0]
|
75
75
|
tb = src.get_fps() if args.timebase is None else args.timebase
|
76
76
|
ensure = Ensure(ffmpeg, src.get_sr(), temp, log)
|
@@ -1,57 +1,22 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import os
|
4
1
|
import sys
|
5
|
-
import tempfile
|
6
|
-
from dataclasses import dataclass, field
|
7
|
-
|
8
|
-
from auto_editor.ffwrapper import FFmpeg, initFileInfo
|
9
|
-
from auto_editor.utils.log import Log
|
10
|
-
from auto_editor.vanparse import ArgumentParser
|
11
|
-
|
12
2
|
|
13
|
-
|
14
|
-
|
15
|
-
ffmpeg_location: str | None = None
|
16
|
-
my_ffmpeg: bool = False
|
17
|
-
help: bool = False
|
18
|
-
input: list[str] = field(default_factory=list)
|
19
|
-
|
20
|
-
|
21
|
-
def subdump_options(parser: ArgumentParser) -> ArgumentParser:
|
22
|
-
parser.add_required("input", nargs="*")
|
23
|
-
parser.add_argument("--ffmpeg-location", help="Point to your custom ffmpeg file")
|
24
|
-
parser.add_argument(
|
25
|
-
"--my-ffmpeg",
|
26
|
-
flag=True,
|
27
|
-
help="Use the ffmpeg on your PATH instead of the one packaged",
|
28
|
-
)
|
29
|
-
return parser
|
3
|
+
import av
|
4
|
+
from av.subtitles.subtitle import SubtitleSet
|
30
5
|
|
31
6
|
|
32
7
|
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
cmd.extend(["-map", f"0:s:{s}", os.path.join(temp, f"{i}s{s}.{sub.ext}")])
|
46
|
-
ffmpeg.run(cmd)
|
47
|
-
|
48
|
-
for s, sub in enumerate(src.subtitles):
|
49
|
-
print(f"file: {input_file} ({s}:{sub.lang}:{sub.ext})")
|
50
|
-
with open(os.path.join(temp, f"{i}s{s}.{sub.ext}")) as file:
|
51
|
-
print(file.read())
|
52
|
-
print("------")
|
53
|
-
|
54
|
-
log.cleanup()
|
8
|
+
for i, input_file in enumerate(sys_args):
|
9
|
+
with av.open(input_file) as container:
|
10
|
+
for s in range(len(container.streams.subtitles)):
|
11
|
+
print(f"file: {input_file} ({s}:{container.streams.subtitles[s].name})")
|
12
|
+
for packet in container.demux(subtitles=s):
|
13
|
+
for item in packet.decode():
|
14
|
+
if type(item) is SubtitleSet and item:
|
15
|
+
if item[0].type == b"ass":
|
16
|
+
print(item[0].ass.decode("utf-8"))
|
17
|
+
elif item[0].type == b"text":
|
18
|
+
print(item[0].text)
|
19
|
+
print("------")
|
55
20
|
|
56
21
|
|
57
22
|
if __name__ == "__main__":
|
auto_editor/subcommands/test.py
CHANGED
@@ -13,7 +13,7 @@ from typing import Any
|
|
13
13
|
|
14
14
|
import numpy as np
|
15
15
|
|
16
|
-
from auto_editor.ffwrapper import
|
16
|
+
from auto_editor.ffwrapper import FileInfo, initFileInfo
|
17
17
|
from auto_editor.lang.palet import Lexer, Parser, env, interpret
|
18
18
|
from auto_editor.lib.data_structs import Char
|
19
19
|
from auto_editor.lib.err import MyError
|
@@ -48,12 +48,11 @@ def pipe_to_console(cmd: list[str]) -> tuple[int, str, str]:
|
|
48
48
|
|
49
49
|
|
50
50
|
class Checker:
|
51
|
-
def __init__(self,
|
52
|
-
self.ffmpeg = ffmpeg
|
51
|
+
def __init__(self, log: Log):
|
53
52
|
self.log = log
|
54
53
|
|
55
54
|
def check(self, path: str) -> FileInfo:
|
56
|
-
return initFileInfo(path, self.
|
55
|
+
return initFileInfo(path, self.log)
|
57
56
|
|
58
57
|
|
59
58
|
class Runner:
|
@@ -177,7 +176,7 @@ def main(sys_args: list[str] | None = None):
|
|
177
176
|
args = test_options(ArgumentParser("test")).parse_args(TestArgs, sys_args)
|
178
177
|
|
179
178
|
run = Runner()
|
180
|
-
checker = Checker(
|
179
|
+
checker = Checker(Log())
|
181
180
|
|
182
181
|
### Tests ###
|
183
182
|
|
@@ -525,7 +524,9 @@ def main(sys_args: list[str] | None = None):
|
|
525
524
|
# Issue 280
|
526
525
|
def SAR():
|
527
526
|
out = run.main(["resources/SAR-2by3.mp4"], [])
|
528
|
-
|
527
|
+
|
528
|
+
# It's working, PyAV just can't detect the changes.
|
529
|
+
# assert checker.check(out).videos[0].sar == Fraction(2, 3)
|
529
530
|
|
530
531
|
return out
|
531
532
|
|
auto_editor/wavfile.py
CHANGED
@@ -45,9 +45,9 @@ def _read_fmt_chunk(
|
|
45
45
|
raw_guid = extensible_chunk_data[6:22]
|
46
46
|
|
47
47
|
if bytes_order == "big":
|
48
|
-
tail = b"\x00\x00\x00\x10\x80\x00\x00\
|
48
|
+
tail = b"\x00\x00\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71"
|
49
49
|
else:
|
50
|
-
tail = b"\x00\x00\x10\x00\x80\x00\x00\
|
50
|
+
tail = b"\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71"
|
51
51
|
if raw_guid.endswith(tail):
|
52
52
|
format_tag = int.from_bytes(raw_guid[:4], bytes_order)
|
53
53
|
else:
|
@@ -249,7 +249,7 @@ def write(fid: io.BufferedWriter, sr: int, arr: np.ndarray) -> None:
|
|
249
249
|
total_size = 44 + data_size # Basic WAV header size + data size
|
250
250
|
|
251
251
|
if is_rf64 := total_size > 0xFFFFFFFF:
|
252
|
-
fid.write(b"RF64\
|
252
|
+
fid.write(b"RF64\xff\xff\xff\xffWAVE")
|
253
253
|
ds64_size = 28
|
254
254
|
ds64_chunk_data = (0).to_bytes(ds64_size, "little") # placeholder values
|
255
255
|
fid.write(b"ds64" + struct.pack("<I", ds64_size) + ds64_chunk_data)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: auto-editor
|
3
|
-
Version: 24.
|
3
|
+
Version: 24.13.1
|
4
4
|
Summary: Auto-Editor: Effort free video editing!
|
5
5
|
Author-email: WyattBlue <wyattblue@auto-editor.com>
|
6
6
|
License: Unlicense
|
@@ -12,8 +12,8 @@ Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
13
13
|
License-File: LICENSE
|
14
14
|
Requires-Dist: numpy >=1.22.0
|
15
|
-
Requires-Dist: pyav ==12.0.
|
16
|
-
Requires-Dist: ae-ffmpeg ==1.
|
15
|
+
Requires-Dist: pyav ==12.0.5
|
16
|
+
Requires-Dist: ae-ffmpeg ==1.2.*
|
17
17
|
|
18
18
|
<p align="center"><img src="https://auto-editor.com/img/auto-editor-banner.webp" title="Auto-Editor" width="700"></p>
|
19
19
|
|
@@ -1,23 +1,23 @@
|
|
1
1
|
ae-ffmpeg/setup.py,sha256=HeORyrs8OyJ32lSnMaIhI2B7U1lkk3QP6wOjxpoiF3Y,1891
|
2
|
-
ae-ffmpeg/ae_ffmpeg/__init__.py,sha256=
|
2
|
+
ae-ffmpeg/ae_ffmpeg/__init__.py,sha256=Fd2YsCINa0dB3tf9VVKDTPT9P6MDH-ve3RT2pqArImI,453
|
3
3
|
ae-ffmpeg/ae_ffmpeg/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
auto_editor/__init__.py,sha256=
|
4
|
+
auto_editor/__init__.py,sha256=oSC_QYd59SbGta8dUWWTRxcFAzDKetEOu5kGPq6yXFE,43
|
5
5
|
auto_editor/__main__.py,sha256=Lb_0h7Zop0SHK-nLWgwp7MWFrznuir8Ilo17Vx_0aKs,9827
|
6
6
|
auto_editor/analyze.py,sha256=zvN4hXyEGXdUUVkfnYlyrCXPgBRl3DoQtBwIfHo7q68,11938
|
7
|
-
auto_editor/edit.py,sha256=
|
8
|
-
auto_editor/ffwrapper.py,sha256=
|
7
|
+
auto_editor/edit.py,sha256=ZH0AgGBCTv_0KTqKbybZWbMCDx_OV_i15PklTGpEBC4,11997
|
8
|
+
auto_editor/ffwrapper.py,sha256=af6j5257npuwJAyHMVKM7BbHGpjZ0bYkN1SGvIGLLu4,7662
|
9
9
|
auto_editor/help.py,sha256=BFiP7vBz42TUzum4-zaQIrV1OY7kHeN0pe0MPE0T5xw,7997
|
10
10
|
auto_editor/make_layers.py,sha256=_YyuV7JvF9sneu3FJQPDkvRqzja8Fzscr4624bXN4iI,8214
|
11
|
-
auto_editor/output.py,sha256=
|
11
|
+
auto_editor/output.py,sha256=ySTt0WiU4-VszsATLxpsz5HIIL-7FzoOm-yJrJRqi3E,6714
|
12
12
|
auto_editor/preview.py,sha256=K10TyP0_LWD4yEIUHzqSHs_97hKl0VIaIuA1xGHI8ZI,3023
|
13
13
|
auto_editor/timeline.py,sha256=JwcS-8AS5vsoTL_m03aosYijScQef4AGa2lyutQ8wbI,7069
|
14
14
|
auto_editor/validate_input.py,sha256=G4LzUdt0fSrIPRd-wvP7x9cOzXmHTd7-BPrFk2ZNEWk,2671
|
15
15
|
auto_editor/vanparse.py,sha256=kHvGK7itqt37q0MPTSriPljB7ilFpjG5LuEVdulUbyg,9902
|
16
|
-
auto_editor/wavfile.py,sha256=
|
16
|
+
auto_editor/wavfile.py,sha256=7N2LX_WfFVRnoXrKveLvuyTYpIz2htpGqfCD8tR4kJ8,9168
|
17
17
|
auto_editor/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
|
-
auto_editor/formats/fcp11.py,sha256=
|
19
|
-
auto_editor/formats/fcp7.py,sha256=
|
20
|
-
auto_editor/formats/json.py,sha256=
|
18
|
+
auto_editor/formats/fcp11.py,sha256=H_zDaKFLUCEgRZGQjDZxqY4kmx0aIvoxWB3PMQXDsiE,5876
|
19
|
+
auto_editor/formats/fcp7.py,sha256=ASmg9m94jaF_bq4uMawShyDi1ztptJHda6uf6SsX1zM,17713
|
20
|
+
auto_editor/formats/json.py,sha256=RG5991SWaBSdbTCg49wJHvKMQM3UG2fM36xzc9aZrX0,6653
|
21
21
|
auto_editor/formats/shotcut.py,sha256=9XM-NGDVSrHyG05Tsq6RR6WacyatQxGa6wPuRu-QtXU,5023
|
22
22
|
auto_editor/formats/utils.py,sha256=GIZw28WHuCIaZ_zMI0v6Kxbq0QaIpbLsdSegdYwQxQ8,1990
|
23
23
|
auto_editor/lang/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -31,15 +31,15 @@ auto_editor/lib/err.py,sha256=UlszQJdzMZwkbT8x3sY4GkCV_5x9yrd6uVVUzvA8iiI,35
|
|
31
31
|
auto_editor/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
32
|
auto_editor/render/audio.py,sha256=lEmPuRKW5QipJV6ncCx8CHjg7wyK1knwqRM5p7zKvBY,8816
|
33
33
|
auto_editor/render/subtitle.py,sha256=D4WDiY4iM9HsNfJvZay7zv_gvZPvyd12nd9Fi9vbPjQ,4646
|
34
|
-
auto_editor/render/video.py,sha256=
|
34
|
+
auto_editor/render/video.py,sha256=ov_AgFbF_6HWuOf1j-7g6sJBNuKyOyPMTAbcftxotaQ,13225
|
35
35
|
auto_editor/subcommands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
36
|
-
auto_editor/subcommands/desc.py,sha256=
|
37
|
-
auto_editor/subcommands/info.py,sha256=
|
38
|
-
auto_editor/subcommands/levels.py,sha256=
|
36
|
+
auto_editor/subcommands/desc.py,sha256=GDrKJYiHMaeTrplZAceXl1JwoqD78XsV2_5lc0Xd7po,869
|
37
|
+
auto_editor/subcommands/info.py,sha256=N6dXeJf8WXAJjVtfY99fQNu2d-kiX86X6SH0QblWkOg,6571
|
38
|
+
auto_editor/subcommands/levels.py,sha256=XHMG3jsdoXBvG0TlP1bBbtjD0m5EgWnOMBTIYx8VAnA,4001
|
39
39
|
auto_editor/subcommands/palet.py,sha256=tbQoRWoT4jR3yu0etGApfprM-oQgXIjC-rIY-QG3nM0,655
|
40
|
-
auto_editor/subcommands/repl.py,sha256=
|
41
|
-
auto_editor/subcommands/subdump.py,sha256=
|
42
|
-
auto_editor/subcommands/test.py,sha256=
|
40
|
+
auto_editor/subcommands/repl.py,sha256=xoNq88PtbvX3r1-FLStOb5jNoJ_rFzrl7R3Tk8a7zyI,3717
|
41
|
+
auto_editor/subcommands/subdump.py,sha256=Bm1PI1Gd2kQR2FFdgG9kXSXSZsAEOsSToSE5_BGF8UA,836
|
42
|
+
auto_editor/subcommands/test.py,sha256=2N1Hk03Oofs9WssvrUfDMaDFEp9ngcu9IwIgXkYfcGk,24810
|
43
43
|
auto_editor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
44
44
|
auto_editor/utils/bar.py,sha256=eWpiXZpRc2v2LW-EaoAgG_cTtMh5275or8Ttda3Ei-I,3974
|
45
45
|
auto_editor/utils/chunks.py,sha256=J-eGKtEz68gFtRrj1kOSgH4Tj_Yz6prNQ7Xr-d9NQJw,52
|
@@ -49,9 +49,9 @@ auto_editor/utils/encoder.py,sha256=auNYo7HXbcU4iTUCc0LE5lpwFmSvdWvBm6-5KIaRK8w,
|
|
49
49
|
auto_editor/utils/func.py,sha256=H38xO6Wxg1TZILVrx-nCowCzj_mqBUtJuOFp4DV3Hsc,4843
|
50
50
|
auto_editor/utils/log.py,sha256=6j2EWE97_urQijBvxhk2Gr2-VO_KNR1XbEobcAtTG-w,2668
|
51
51
|
auto_editor/utils/types.py,sha256=aWyJpVBjmctxlxiL5o8r6lplKnaFSjVNQlcoXFgfmSk,11533
|
52
|
-
auto_editor-24.
|
53
|
-
auto_editor-24.
|
54
|
-
auto_editor-24.
|
55
|
-
auto_editor-24.
|
56
|
-
auto_editor-24.
|
57
|
-
auto_editor-24.
|
52
|
+
auto_editor-24.13.1.dist-info/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
|
53
|
+
auto_editor-24.13.1.dist-info/METADATA,sha256=JTShKvxQqosFX0sXVjMyPrYx_OVJJ5zkXnc8Na8wAX0,7093
|
54
|
+
auto_editor-24.13.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
55
|
+
auto_editor-24.13.1.dist-info/entry_points.txt,sha256=-H7zdTw4MqnAcwrN5xTNkGIhzZtJMxS9r6lTMeR9-aA,240
|
56
|
+
auto_editor-24.13.1.dist-info/top_level.txt,sha256=xwV1JV1ZeRmlH9VeBRZXgXtWHpWSD4w1mY5II56D3ns,22
|
57
|
+
auto_editor-24.13.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|