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.
@@ -1,4 +1,4 @@
1
- __version__ = "1.1.2"
1
+ __version__ = "1.2.0"
2
2
 
3
3
  import os.path
4
4
  from platform import machine, system
auto_editor/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "24.9.1"
2
- version = "24w09a"
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], ffmpeg, log)
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, ffmpeg, log) for path in paths]
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: str | None
139
- color_space: str | None
140
- color_primaries: str | None
141
- color_transfer: str | None
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, ffmpeg: FFmpeg, log: Log) -> FileInfo:
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
- _dir = os.path.dirname(ffmpeg.path)
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
- _sar = c_range = c_space = c_primary = c_transfer = None
222
- try:
223
- _raw = get_stdout(
224
- [
225
- ffprobe,
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
- v.codec_context.pix_fmt,
262
- c_range,
263
- c_space,
264
- c_primary,
265
- c_transfer,
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
- a.codec_context.name,
279
- 0 if a.sample_rate is None else a.sample_rate,
280
- a.channels,
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 a.bit_rate is None else a.bit_rate,
255
+ 0 if a_cc.bit_rate is None else a_cc.bit_rate,
283
256
  a.language,
284
257
  ),
285
258
  )
@@ -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 == "smpte170m":
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.color_primaries == "bt2020":
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", "smpte2084"):
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}", ffmpeg, log))
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")
@@ -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"]), ffmpeg, log
317
+ uri_to_path(fileobj["pathurl"]), log
319
318
  )
320
319
 
321
320
  if "filter" in clipitem:
@@ -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 FFmpeg, FileInfo, initFileInfo
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, ffmpeg: FFmpeg, log: Log) -> v3:
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, ffmpeg, log)
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, ffmpeg: FFmpeg, log: Log) -> v3:
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, ffmpeg, log)
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, ffmpeg: FFmpeg, log: Log) -> v3:
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, ffmpeg, log)
209
+ return read_v3(tl, log)
210
210
  if ver == "1":
211
- return read_v1(tl, ffmpeg, log)
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
- cmd += (
186
- _ffset("-color_range", src.videos[0].color_range)
187
- + _ffset("-colorspace", src.videos[0].color_space)
188
- + _ffset("-color_primaries", src.videos[0].color_primaries)
189
- + _ffset("-color_trc", src.videos[0].color_transfer)
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(" "))
@@ -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:
@@ -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 FFmpeg, initFileInfo
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, FFmpeg(args.ffmpeg_location), Log())
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:
@@ -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 FFmpeg, initFileInfo
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: str | None
46
- color_space: str | None
47
- color_primaries: str | None
48
- color_transfer: str | None
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, ffmpeg, log)
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, ffmpeg, log)
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
- text += f" - {key}: {value}\n"
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, ffmpeg, log) for path in args.input]
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
 
@@ -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, ffmpeg, log) for path in args.input]
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
- @dataclass(slots=True)
14
- class SubArgs:
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
- args = subdump_options(ArgumentParser("subdump")).parse_args(SubArgs, sys_args)
34
-
35
- ffmpeg = FFmpeg(args.ffmpeg_location, args.my_ffmpeg, debug=False)
36
-
37
- temp = tempfile.mkdtemp()
38
- log = Log(temp=temp)
39
-
40
- for i, input_file in enumerate(args.input):
41
- src = initFileInfo(input_file, ffmpeg, log)
42
-
43
- cmd = ["-i", input_file]
44
- for s, sub in enumerate(src.subtitles):
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__":
@@ -13,7 +13,7 @@ from typing import Any
13
13
 
14
14
  import numpy as np
15
15
 
16
- from auto_editor.ffwrapper import FFmpeg, FileInfo, initFileInfo
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, ffmpeg: FFmpeg, log: Log):
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.ffmpeg, self.log)
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(FFmpeg(), Log())
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
- assert checker.check(out).videos[0].sar == Fraction(2, 3)
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\xAA\x00\x38\x9B\x71"
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\xAA\x00\x38\x9B\x71"
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\xFF\xFF\xFF\xFFWAVE")
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.9.1
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.2
16
- Requires-Dist: ae-ffmpeg ==1.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=Y_dn5Uoh1fOrhhJ9B3agOsPF2VXnCbIaXuN3ZRft-pk,453
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=RJIMlcL3cdE7LOygV0nkUUrFZqTrOQb2DimvfAvLfF8,42
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=oL8-oCHMbTARb89IY4tsnSs_vWeqk6lwVvNhdw4Xp5M,12013
8
- auto_editor/ffwrapper.py,sha256=TrYdEyjzbpRif4mGWfi8FHkRl5chbI07-tUUyg-CpBA,8667
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=NkdwGbiUAXvieOqjmsH4jMj3pplSKAOrbhN503U2o-o,6311
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=UatK5yRJGe2vIpHC1U0ccxyixaLyzLoNvApzWcrxLy8,9168
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=3Z7-AYkGmlnk2WyzNG11483krZqj3XRAnvw491RTxHE,5860
19
- auto_editor/formats/fcp7.py,sha256=zzkcq6U0NYlckc1X81ioStd4QbdN4pj_de4EHlV5dbo,17757
20
- auto_editor/formats/json.py,sha256=AFrQwjzmMMoEJFgYNEipnz2X75ftRfHmPHJKWW_KPwo,6741
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=LufVJJW-r0_5xWSGGpOIH3Clh63FWxEJuct-TORErDQ,13286
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=CWnRk3LCTV_sMVJVA45ZMBfPy_ESfwqkySMVuW8Fbrg,1032
37
- auto_editor/subcommands/info.py,sha256=etsjaKBEy0AxDtZ7XZNiizSmBnx8Wf2HeRfUyPyBCqA,6237
38
- auto_editor/subcommands/levels.py,sha256=utCuRmpa2mirnQ_t1ogPexqjZAUBTC9KrCSS_BbSyBg,4009
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=j5jxWgscaaRULa6ZsrV4tDJQB4vOzxiEQR0jI90v5s0,3725
41
- auto_editor/subcommands/subdump.py,sha256=GGekYMnqLkcqfihKjlHcuWkMazvgsYTF0q4ulEDOrRc,1669
42
- auto_editor/subcommands/test.py,sha256=YOhmvehSohM1nCbU-Ivub_xEJEM57NwHuadLbrojJ84,24823
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.9.1.dist-info/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
53
- auto_editor-24.9.1.dist-info/METADATA,sha256=KeE8QXLu3b7IVUd5-3c6A_rax_5LXoqzuSN96wKp4gk,7092
54
- auto_editor-24.9.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
55
- auto_editor-24.9.1.dist-info/entry_points.txt,sha256=-H7zdTw4MqnAcwrN5xTNkGIhzZtJMxS9r6lTMeR9-aA,240
56
- auto_editor-24.9.1.dist-info/top_level.txt,sha256=xwV1JV1ZeRmlH9VeBRZXgXtWHpWSD4w1mY5II56D3ns,22
57
- auto_editor-24.9.1.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.42.0)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5