auto-editor 24.13.1__tar.gz → 24.24.1__tar.gz
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.
- {auto-editor-24.13.1/auto_editor.egg-info → auto_editor-24.24.1}/PKG-INFO +11 -36
- {auto-editor-24.13.1 → auto_editor-24.24.1}/README.md +9 -34
- auto_editor-24.24.1/auto_editor/__init__.py +2 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/__main__.py +6 -5
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/analyze.py +2 -11
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/edit.py +2 -3
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/ffwrapper.py +0 -2
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/formats/fcp11.py +1 -1
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/formats/fcp7.py +6 -6
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/formats/json.py +24 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/formats/shotcut.py +3 -3
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/make_layers.py +36 -29
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/preview.py +2 -1
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/render/audio.py +2 -2
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/render/video.py +1 -4
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/subcommands/info.py +9 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/subcommands/subdump.py +7 -7
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/utils/bar.py +2 -2
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/utils/container.py +7 -7
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/utils/log.py +5 -2
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/utils/types.py +5 -4
- {auto-editor-24.13.1 → auto_editor-24.24.1/auto_editor.egg-info}/PKG-INFO +11 -36
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor.egg-info/requires.txt +1 -1
- {auto-editor-24.13.1 → auto_editor-24.24.1}/pyproject.toml +1 -1
- auto-editor-24.13.1/auto_editor/__init__.py +0 -2
- {auto-editor-24.13.1 → auto_editor-24.24.1}/LICENSE +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/ae-ffmpeg/ae_ffmpeg/__init__.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/ae-ffmpeg/ae_ffmpeg/py.typed +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/ae-ffmpeg/setup.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/formats/__init__.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/formats/utils.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/help.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/lang/__init__.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/lang/json.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/lang/libmath.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/lang/palet.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/lib/__init__.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/lib/contracts.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/lib/data_structs.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/lib/err.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/output.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/render/__init__.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/render/subtitle.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/subcommands/__init__.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/subcommands/desc.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/subcommands/levels.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/subcommands/palet.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/subcommands/repl.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/subcommands/test.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/timeline.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/utils/__init__.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/utils/chunks.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/utils/cmdkw.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/utils/encoder.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/utils/func.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/validate_input.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/vanparse.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor/wavfile.py +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor.egg-info/SOURCES.txt +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor.egg-info/dependency_links.txt +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor.egg-info/entry_points.txt +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/auto_editor.egg-info/top_level.txt +0 -0
- {auto-editor-24.13.1 → auto_editor-24.24.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: auto-editor
|
3
|
-
Version: 24.
|
3
|
+
Version: 24.24.1
|
4
4
|
Summary: Auto-Editor: Effort free video editing!
|
5
5
|
Author-email: WyattBlue <wyattblue@auto-editor.com>
|
6
6
|
License: Unlicense
|
@@ -12,7 +12,7 @@ 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
|
15
|
+
Requires-Dist: pyav==12.1.0
|
16
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>
|
@@ -60,10 +60,10 @@ The `--edit` option is how auto-editor makes automated cuts.
|
|
60
60
|
For example, edit out motionlessness in a video by setting `--edit motion`.
|
61
61
|
|
62
62
|
```
|
63
|
-
# cut out sections where
|
64
|
-
auto-editor example.mp4 --edit motion:threshold=
|
63
|
+
# cut out sections where the total motion is less than 2%.
|
64
|
+
auto-editor example.mp4 --edit motion:threshold=0.02
|
65
65
|
|
66
|
-
#
|
66
|
+
# `--edit audio:threshold=0.04,stream=all` is used by defaut.
|
67
67
|
auto-editor example.mp4
|
68
68
|
|
69
69
|
# Different tracks can be set with different attribute.
|
@@ -73,34 +73,14 @@ auto-editor multi-track.mov --edit "(or audio:stream=0 audio:threshold=10%,strea
|
|
73
73
|
Different editing methods can be used together.
|
74
74
|
```
|
75
75
|
# 'threshold' is always the first argument for edit-method objects
|
76
|
-
auto-editor example.mp4 --edit "(or audio:
|
76
|
+
auto-editor example.mp4 --edit "(or audio:0.03 motion:0.06)"
|
77
77
|
```
|
78
78
|
|
79
79
|
You can also use `dB` unit, a volume unit familiar to video-editors (case sensitive):
|
80
80
|
```
|
81
|
-
auto-editor example.mp4 --edit audio
|
81
|
+
auto-editor example.mp4 --edit audio:-19dB
|
82
82
|
auto-editor example.mp4 --edit audio:-7dB
|
83
83
|
auto-editor example.mp4 --edit motion:-19dB
|
84
|
-
|
85
|
-
# The `dB` unit is a just a macro that expands into an S-expression:
|
86
|
-
# '-19dB
|
87
|
-
# > '(pow 10 (/ -19 20))
|
88
|
-
# (eval '(pow 10 (/ -19 20)))
|
89
|
-
# > 0.11220184543019636
|
90
|
-
```
|
91
|
-
|
92
|
-
### Working With Multiple Audio Tracks
|
93
|
-
By default, only the first audio track will used for editing (track 0). You can change this with these commands.
|
94
|
-
|
95
|
-
Use all audio tracks for editing:
|
96
|
-
```
|
97
|
-
auto-editor multi-track.mov --edit audio:stream=all
|
98
|
-
```
|
99
|
-
|
100
|
-
Use only the second, fourth, and sixth audio track:
|
101
|
-
```
|
102
|
-
# track numbers start at 0
|
103
|
-
auto-editor so-many-tracks.mp4 --edit "(or audio:stream=1 audio:stream=3 audio:stream=5)"
|
104
84
|
```
|
105
85
|
|
106
86
|
### See What Auto-Editor Cuts Out
|
@@ -119,12 +99,10 @@ auto-editor example.mp4 --export premiere
|
|
119
99
|
```
|
120
100
|
|
121
101
|
Auto-Editor can also export to:
|
122
|
-
|
123
102
|
- DaVinci Resolve with `--export resolve`
|
124
103
|
- Final Cut Pro with `--export final-cut-pro`
|
125
104
|
- ShotCut with `--export shotcut`
|
126
|
-
|
127
|
-
Other editors, like Sony Vegas, can understand the `premiere` format. If your favorite editor doesn't, you can use ` --export clip-sequence` which creates many video clips that can be imported and manipulated like normal.
|
105
|
+
- Individual media clips with `--export clip-sequence`
|
128
106
|
|
129
107
|
### Naming Timelines
|
130
108
|
By default, auto-editor will name the timeline to "Auto-Editor Media Group" if the export supports naming.
|
@@ -188,14 +166,11 @@ List all available options:
|
|
188
166
|
auto-editor --help
|
189
167
|
```
|
190
168
|
|
191
|
-
Use `--help` with a specific option
|
169
|
+
Use `--help` with a specific option to learn more about it:
|
192
170
|
|
193
171
|
```
|
194
|
-
auto-editor
|
195
|
-
|
196
|
-
|
197
|
-
default: 1.0
|
198
|
-
Scale the output video's resolution by NUM factor
|
172
|
+
auto-editor -c:v --help
|
173
|
+
auto-editor --margin --help
|
199
174
|
```
|
200
175
|
|
201
176
|
<h3 align="center">Auto-Editor is available on all major platforms</h3>
|
@@ -43,10 +43,10 @@ The `--edit` option is how auto-editor makes automated cuts.
|
|
43
43
|
For example, edit out motionlessness in a video by setting `--edit motion`.
|
44
44
|
|
45
45
|
```
|
46
|
-
# cut out sections where
|
47
|
-
auto-editor example.mp4 --edit motion:threshold=
|
46
|
+
# cut out sections where the total motion is less than 2%.
|
47
|
+
auto-editor example.mp4 --edit motion:threshold=0.02
|
48
48
|
|
49
|
-
#
|
49
|
+
# `--edit audio:threshold=0.04,stream=all` is used by defaut.
|
50
50
|
auto-editor example.mp4
|
51
51
|
|
52
52
|
# Different tracks can be set with different attribute.
|
@@ -56,34 +56,14 @@ auto-editor multi-track.mov --edit "(or audio:stream=0 audio:threshold=10%,strea
|
|
56
56
|
Different editing methods can be used together.
|
57
57
|
```
|
58
58
|
# 'threshold' is always the first argument for edit-method objects
|
59
|
-
auto-editor example.mp4 --edit "(or audio:
|
59
|
+
auto-editor example.mp4 --edit "(or audio:0.03 motion:0.06)"
|
60
60
|
```
|
61
61
|
|
62
62
|
You can also use `dB` unit, a volume unit familiar to video-editors (case sensitive):
|
63
63
|
```
|
64
|
-
auto-editor example.mp4 --edit audio
|
64
|
+
auto-editor example.mp4 --edit audio:-19dB
|
65
65
|
auto-editor example.mp4 --edit audio:-7dB
|
66
66
|
auto-editor example.mp4 --edit motion:-19dB
|
67
|
-
|
68
|
-
# The `dB` unit is a just a macro that expands into an S-expression:
|
69
|
-
# '-19dB
|
70
|
-
# > '(pow 10 (/ -19 20))
|
71
|
-
# (eval '(pow 10 (/ -19 20)))
|
72
|
-
# > 0.11220184543019636
|
73
|
-
```
|
74
|
-
|
75
|
-
### Working With Multiple Audio Tracks
|
76
|
-
By default, only the first audio track will used for editing (track 0). You can change this with these commands.
|
77
|
-
|
78
|
-
Use all audio tracks for editing:
|
79
|
-
```
|
80
|
-
auto-editor multi-track.mov --edit audio:stream=all
|
81
|
-
```
|
82
|
-
|
83
|
-
Use only the second, fourth, and sixth audio track:
|
84
|
-
```
|
85
|
-
# track numbers start at 0
|
86
|
-
auto-editor so-many-tracks.mp4 --edit "(or audio:stream=1 audio:stream=3 audio:stream=5)"
|
87
67
|
```
|
88
68
|
|
89
69
|
### See What Auto-Editor Cuts Out
|
@@ -102,12 +82,10 @@ auto-editor example.mp4 --export premiere
|
|
102
82
|
```
|
103
83
|
|
104
84
|
Auto-Editor can also export to:
|
105
|
-
|
106
85
|
- DaVinci Resolve with `--export resolve`
|
107
86
|
- Final Cut Pro with `--export final-cut-pro`
|
108
87
|
- ShotCut with `--export shotcut`
|
109
|
-
|
110
|
-
Other editors, like Sony Vegas, can understand the `premiere` format. If your favorite editor doesn't, you can use ` --export clip-sequence` which creates many video clips that can be imported and manipulated like normal.
|
88
|
+
- Individual media clips with `--export clip-sequence`
|
111
89
|
|
112
90
|
### Naming Timelines
|
113
91
|
By default, auto-editor will name the timeline to "Auto-Editor Media Group" if the export supports naming.
|
@@ -171,14 +149,11 @@ List all available options:
|
|
171
149
|
auto-editor --help
|
172
150
|
```
|
173
151
|
|
174
|
-
Use `--help` with a specific option
|
152
|
+
Use `--help` with a specific option to learn more about it:
|
175
153
|
|
176
154
|
```
|
177
|
-
auto-editor
|
178
|
-
|
179
|
-
|
180
|
-
default: 1.0
|
181
|
-
Scale the output video's resolution by NUM factor
|
155
|
+
auto-editor -c:v --help
|
156
|
+
auto-editor --margin --help
|
182
157
|
```
|
183
158
|
|
184
159
|
<h3 align="center">Auto-Editor is available on all major platforms</h3>
|
@@ -4,7 +4,7 @@ import sys
|
|
4
4
|
|
5
5
|
import auto_editor
|
6
6
|
from auto_editor.utils.func import setup_tempdir
|
7
|
-
from auto_editor.utils.log import Log
|
7
|
+
from auto_editor.utils.log import Log, Timer
|
8
8
|
from auto_editor.utils.types import (
|
9
9
|
Args,
|
10
10
|
bitrate,
|
@@ -312,8 +312,7 @@ def main() -> None:
|
|
312
312
|
if args.debug and args.input == []:
|
313
313
|
import platform as plat
|
314
314
|
|
315
|
-
|
316
|
-
print(f"Python Version: {plat.python_version()} {is64bit}")
|
315
|
+
print(f"Python Version: {plat.python_version()}")
|
317
316
|
print(f"Platform: {plat.system()} {plat.release()} {plat.machine().lower()}")
|
318
317
|
print(f"FFmpeg Version: {ffmpeg.version}\nFFmpeg Path: {ffmpeg.path}")
|
319
318
|
print(f"Auto-Editor Version: {auto_editor.version}")
|
@@ -323,13 +322,15 @@ def main() -> None:
|
|
323
322
|
log.error("You need to give auto-editor an input file.")
|
324
323
|
|
325
324
|
temp = setup_tempdir(args.temp_dir, Log())
|
326
|
-
log = Log(args.debug, args.quiet, temp
|
325
|
+
log = Log(args.debug, args.quiet, temp)
|
326
|
+
log.machine = args.progress == "machine"
|
327
327
|
log.debug(f"Temp Directory: {temp}")
|
328
328
|
|
329
329
|
paths = valid_input(args.input, ffmpeg, args, log)
|
330
|
+
timer = Timer(args.quiet or log.machine)
|
330
331
|
|
331
332
|
try:
|
332
|
-
edit_media(paths, ffmpeg, args, temp, log)
|
333
|
+
edit_media(paths, ffmpeg, args, temp, timer, log)
|
333
334
|
except KeyboardInterrupt:
|
334
335
|
log.error("Keyboard Interrupt")
|
335
336
|
log.cleanup()
|
@@ -170,8 +170,6 @@ class Levels:
|
|
170
170
|
# If there's no audio, get length in video metadata.
|
171
171
|
import av
|
172
172
|
|
173
|
-
av.logging.set_level(av.logging.PANIC)
|
174
|
-
|
175
173
|
with av.open(f"{self.src.path}") as cn:
|
176
174
|
if len(cn.streams.video) < 1:
|
177
175
|
self.log.error("Could not get media duration")
|
@@ -227,11 +225,7 @@ class Levels:
|
|
227
225
|
except Exception:
|
228
226
|
json_object = {}
|
229
227
|
|
230
|
-
entry = {
|
231
|
-
"type": str(arr.dtype),
|
232
|
-
"arr": arr.tolist(),
|
233
|
-
}
|
234
|
-
|
228
|
+
entry = {"type": str(arr.dtype), "arr": arr.tolist()}
|
235
229
|
src_key = f"{self.src.path}"
|
236
230
|
|
237
231
|
if src_key in json_object:
|
@@ -344,13 +338,10 @@ class Levels:
|
|
344
338
|
def motion(self, s: int, blur: int, width: int) -> NDArray[np.float64]:
|
345
339
|
import av
|
346
340
|
|
347
|
-
av.logging.set_level(av.logging.PANIC)
|
348
|
-
|
349
|
-
mobj = {"stream": s, "width": width, "blur": blur}
|
350
|
-
|
351
341
|
if s >= len(self.src.videos):
|
352
342
|
raise LevelError(f"motion: video stream '{s}' does not exist.")
|
353
343
|
|
344
|
+
mobj = {"stream": s, "width": width, "blur": blur}
|
354
345
|
if (arr := self.read_cache("motion", mobj)) is not None:
|
355
346
|
return arr
|
356
347
|
|
@@ -150,9 +150,8 @@ def parse_export(export: str, log: Log) -> dict[str, Any]:
|
|
150
150
|
|
151
151
|
|
152
152
|
def edit_media(
|
153
|
-
paths: list[str], ffmpeg: FFmpeg, args: Args, temp: str, log: Log
|
153
|
+
paths: list[str], ffmpeg: FFmpeg, args: Args, temp: str, timer: Timer, log: Log
|
154
154
|
) -> None:
|
155
|
-
timer = Timer(args.quiet)
|
156
155
|
bar = Bar(args.progress)
|
157
156
|
tl = None
|
158
157
|
|
@@ -223,7 +222,7 @@ def edit_media(
|
|
223
222
|
cmd.extend([os.path.join(temp, f"{s}s.{sub.ext}")])
|
224
223
|
ffmpeg.run(cmd)
|
225
224
|
|
226
|
-
tl = make_timeline(sources,
|
225
|
+
tl = make_timeline(sources, ensure, args, samplerate, bar, temp, log)
|
227
226
|
|
228
227
|
if export["export"] == "timeline":
|
229
228
|
from auto_editor.formats.json import make_json_timeline
|
@@ -140,7 +140,7 @@ def fcp11_write_xml(
|
|
140
140
|
"ref": ref,
|
141
141
|
"offset": fraction(clip.start),
|
142
142
|
"duration": fraction(clip.dur),
|
143
|
-
"start": fraction(
|
143
|
+
"start": fraction(clip.offset),
|
144
144
|
"tcFormat": "NDF",
|
145
145
|
}
|
146
146
|
asset = SubElement(spine, "asset-clip", clip_properties)
|
@@ -296,7 +296,7 @@ def fcp7_read_xml(path: str, ffmpeg: FFmpeg, log: Log) -> v3:
|
|
296
296
|
|
297
297
|
start = clipitem["start"]
|
298
298
|
dur = clipitem["end"] - start
|
299
|
-
offset =
|
299
|
+
offset = clipitem["in"]
|
300
300
|
|
301
301
|
vobjs[t].append(
|
302
302
|
TlVideo(start, dur, sources[file_id], offset, speed, stream=0)
|
@@ -324,7 +324,7 @@ def fcp7_read_xml(path: str, ffmpeg: FFmpeg, log: Log) -> v3:
|
|
324
324
|
|
325
325
|
start = clipitem["start"]
|
326
326
|
dur = clipitem["end"] - start
|
327
|
-
offset =
|
327
|
+
offset = clipitem["in"]
|
328
328
|
|
329
329
|
aobjs[t].append(
|
330
330
|
TlAudio(
|
@@ -414,8 +414,8 @@ def fcp7_write_xml(name: str, output: str, tl: v3, log: Log) -> None:
|
|
414
414
|
|
415
415
|
_start = f"{clip.start}"
|
416
416
|
_end = f"{clip.start + clip.dur}"
|
417
|
-
_in = f"{
|
418
|
-
_out = f"{
|
417
|
+
_in = f"{clip.offset}"
|
418
|
+
_out = f"{clip.offset + clip.dur}"
|
419
419
|
|
420
420
|
clipitem = ET.SubElement(track, "clipitem", id=f"clipitem-{j+1}")
|
421
421
|
ET.SubElement(clipitem, "name").text = src.path.stem
|
@@ -473,8 +473,8 @@ def fcp7_write_xml(name: str, output: str, tl: v3, log: Log) -> None:
|
|
473
473
|
|
474
474
|
_start = f"{aclip.start}"
|
475
475
|
_end = f"{aclip.start + aclip.dur}"
|
476
|
-
_in = f"{
|
477
|
-
_out = f"{
|
476
|
+
_in = f"{aclip.offset}"
|
477
|
+
_out = f"{aclip.offset + aclip.dur}"
|
478
478
|
|
479
479
|
if not src.videos:
|
480
480
|
clip_item_num = j + 1
|
@@ -173,6 +173,30 @@ def read_v1(tl: Any, log: Log) -> v3:
|
|
173
173
|
vtl: VSpace = []
|
174
174
|
atl: ASpace = [[] for _ in range(len(src.audios))]
|
175
175
|
|
176
|
+
# Verify chunks
|
177
|
+
last_end: int | None = None
|
178
|
+
if type(chunks) is not list:
|
179
|
+
log.error("chunks key must be an array")
|
180
|
+
|
181
|
+
for i, chunk in enumerate(chunks):
|
182
|
+
if type(chunk) is not list or len(chunk) != 3:
|
183
|
+
log.error(f"Invalid chunk at chunk {i}")
|
184
|
+
if type(chunk[0]) not in (int, float) or chunk[0] < 0:
|
185
|
+
log.error(f"Invalid start at chunk {i}")
|
186
|
+
if type(chunk[1]) not in (int, float) or chunk[1] <= chunk[0]:
|
187
|
+
log.error(f"Invalid end at chunk {i}")
|
188
|
+
if type(chunk[2]) not in (int, float) or chunk[2] < 0.0 or chunk[2] > 99999.0:
|
189
|
+
log.error(f"Invalid speed at chunk {i}")
|
190
|
+
|
191
|
+
if i == 0 and chunk[0] != 0:
|
192
|
+
log.error("First chunk must start with 0")
|
193
|
+
if i != 0 and chunk[0] != last_end:
|
194
|
+
log.error(f"Invalid start at chunk {i}")
|
195
|
+
last_end = chunk[1]
|
196
|
+
|
197
|
+
if type(chunk[0]) is float or type(chunk[1]) is float or type(chunk[2]) is int:
|
198
|
+
chunks[i] = (int(chunk[0]), int(chunk[1]), float(chunk[2]))
|
199
|
+
|
176
200
|
for c in clipify(chunks, src):
|
177
201
|
if src.videos:
|
178
202
|
if len(vtl) == 0:
|
@@ -92,7 +92,7 @@ def shotcut_write_mlt(output: str, tl: v3) -> None:
|
|
92
92
|
|
93
93
|
for clip in clips:
|
94
94
|
src = clip.src
|
95
|
-
length = to_timecode((clip.offset
|
95
|
+
length = to_timecode((clip.offset + clip.dur) / tb, "standard")
|
96
96
|
|
97
97
|
if clip.speed == 1:
|
98
98
|
resource = f"{src.path}"
|
@@ -127,8 +127,8 @@ def shotcut_write_mlt(output: str, tl: v3) -> None:
|
|
127
127
|
|
128
128
|
producers = 0
|
129
129
|
for i, clip in enumerate(clips):
|
130
|
-
_in = to_timecode(clip.offset /
|
131
|
-
_out = to_timecode((clip.offset
|
130
|
+
_in = to_timecode(clip.offset / tb, "standard")
|
131
|
+
_out = to_timecode((clip.offset + clip.dur) / tb, "standard")
|
132
132
|
|
133
133
|
tag_name = f"chain{i}"
|
134
134
|
if clip.speed != 1:
|
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, NamedTuple
|
|
6
6
|
import numpy as np
|
7
7
|
|
8
8
|
from auto_editor.analyze import FileSetup, Levels
|
9
|
-
from auto_editor.ffwrapper import
|
9
|
+
from auto_editor.ffwrapper import FileInfo
|
10
10
|
from auto_editor.lang.palet import Lexer, Parser, env, interpret, is_boolarr
|
11
11
|
from auto_editor.lib.data_structs import print_str
|
12
12
|
from auto_editor.lib.err import MyError
|
@@ -42,7 +42,7 @@ def clipify(chunks: Chunks, src: FileInfo, start: int = 0) -> list[Clip]:
|
|
42
42
|
if dur == 0:
|
43
43
|
continue
|
44
44
|
|
45
|
-
offset = chunk[0]
|
45
|
+
offset = int(chunk[0] / chunk[2])
|
46
46
|
|
47
47
|
if not (clips and clips[-1].start == round(start)):
|
48
48
|
clips.append(Clip(start, dur, offset, chunk[2], src))
|
@@ -110,9 +110,29 @@ def run_interpreter_for_edit_option(
|
|
110
110
|
return result
|
111
111
|
|
112
112
|
|
113
|
+
def make_sane_timebase(fps: Fraction) -> Fraction:
|
114
|
+
tb = round(fps, 2)
|
115
|
+
ntsc = Fraction(30_000, 1001)
|
116
|
+
film_ntsc = Fraction(24_000, 1001)
|
117
|
+
if tb == round(ntsc, 2):
|
118
|
+
return ntsc
|
119
|
+
if tb == round(film_ntsc, 2):
|
120
|
+
return film_ntsc
|
121
|
+
return tb
|
122
|
+
|
123
|
+
|
124
|
+
def parse_time(val: str, arr: NDArray, tb: Fraction) -> int: # raises: `CoerceError`
|
125
|
+
if val == "start":
|
126
|
+
return 0
|
127
|
+
if val == "end":
|
128
|
+
return len(arr)
|
129
|
+
|
130
|
+
num = time(val, tb)
|
131
|
+
return num if num >= 0 else num + len(arr)
|
132
|
+
|
133
|
+
|
113
134
|
def make_timeline(
|
114
135
|
sources: list[FileInfo],
|
115
|
-
ffmpeg: FFmpeg,
|
116
136
|
ensure: Ensure,
|
117
137
|
args: Args,
|
118
138
|
sr: int,
|
@@ -125,7 +145,9 @@ def make_timeline(
|
|
125
145
|
if inp is None:
|
126
146
|
tb, res = Fraction(30), (1920, 1080)
|
127
147
|
else:
|
128
|
-
tb =
|
148
|
+
tb = make_sane_timebase(
|
149
|
+
inp.get_fps() if args.frame_rate is None else args.frame_rate
|
150
|
+
)
|
129
151
|
res = inp.get_res() if args.resolution is None else args.resolution
|
130
152
|
|
131
153
|
try:
|
@@ -164,36 +186,21 @@ def make_timeline(
|
|
164
186
|
speed_hash[len(speed_map) - 1] = speed
|
165
187
|
return len(speed_map) - 1
|
166
188
|
|
167
|
-
def parse_time(val: str, arr: NDArray) -> int:
|
168
|
-
if val == "start":
|
169
|
-
return 0
|
170
|
-
if val == "end":
|
171
|
-
return len(arr)
|
172
|
-
try:
|
173
|
-
num = time(val, tb)
|
174
|
-
return num if num >= 0 else num + len(arr)
|
175
|
-
except CoerceError as e:
|
176
|
-
log.error(e)
|
177
|
-
|
178
|
-
def mut_set_range(arr: NDArray, _ranges: list[list[str]], index: float) -> None:
|
179
|
-
for _range in _ranges:
|
180
|
-
assert len(_range) == 2
|
181
|
-
pair = [parse_time(val, arr) for val in _range]
|
182
|
-
arr[pair[0] : pair[1]] = index
|
183
|
-
|
184
189
|
try:
|
185
|
-
|
190
|
+
for _range in args.cut_out:
|
186
191
|
# always cut out even if 'silent_speed' is not 99,999
|
187
|
-
|
192
|
+
pair = [parse_time(val, speed_index, tb) for val in _range]
|
193
|
+
speed_index[pair[0] : pair[1]] = get_speed_index(99_999)
|
188
194
|
|
189
|
-
|
195
|
+
for _range in args.add_in:
|
190
196
|
# set to 'video_speed' index
|
191
|
-
|
197
|
+
pair = [parse_time(val, speed_index, tb) for val in _range]
|
198
|
+
speed_index[pair[0] : pair[1]] = 1
|
192
199
|
|
193
200
|
for speed_range in args.set_speed_for_range:
|
194
|
-
|
195
|
-
|
196
|
-
|
201
|
+
start_in = parse_time(speed_range[1], speed_index, tb)
|
202
|
+
end_in = parse_time(speed_range[2], speed_index, tb)
|
203
|
+
speed_index[start_in:end_in] = get_speed_index(speed_range[0])
|
197
204
|
except CoerceError as e:
|
198
205
|
log.error(e)
|
199
206
|
|
@@ -228,7 +235,7 @@ def make_timeline(
|
|
228
235
|
if dur == 0:
|
229
236
|
continue
|
230
237
|
|
231
|
-
offset = chunk[1]
|
238
|
+
offset = int(chunk[1] / chunk[3])
|
232
239
|
|
233
240
|
if not (clips and clips[-1].start == round(start)):
|
234
241
|
clips.append(Clip(start, dur, offset, chunk[3], chunk[0]))
|
@@ -32,7 +32,8 @@ def all_cuts(tl: v3, in_len: int) -> list[int]:
|
|
32
32
|
oe: list[tuple[int, int]] = []
|
33
33
|
|
34
34
|
for clip in tl.a[0]:
|
35
|
-
|
35
|
+
old_offset = clip.offset * clip.speed
|
36
|
+
oe.append((round(old_offset * clip.speed), round(old_offset + clip.dur)))
|
36
37
|
|
37
38
|
cut_lens = []
|
38
39
|
i = 0
|
@@ -208,8 +208,8 @@ def make_new_audio(
|
|
208
208
|
del leng
|
209
209
|
|
210
210
|
samp_list = samples[(clip.src, clip.stream)]
|
211
|
-
samp_start = clip.offset * sr
|
212
|
-
samp_end = round((clip.offset + clip.dur * clip.speed
|
211
|
+
samp_start = round(clip.offset * clip.speed * sr / tb)
|
212
|
+
samp_end = round((clip.offset + clip.dur) * clip.speed * sr / tb)
|
213
213
|
if samp_end > len(samp_list):
|
214
214
|
samp_end = len(samp_list)
|
215
215
|
|
@@ -27,9 +27,6 @@ if TYPE_CHECKING:
|
|
27
27
|
from auto_editor.utils.types import Args
|
28
28
|
|
29
29
|
|
30
|
-
av.logging.set_level(av.logging.PANIC)
|
31
|
-
|
32
|
-
|
33
30
|
@dataclass(slots=True)
|
34
31
|
class VideoFrame:
|
35
32
|
index: int
|
@@ -244,7 +241,7 @@ def render_av(
|
|
244
241
|
for lobj in layer:
|
245
242
|
if isinstance(lobj, TlVideo):
|
246
243
|
if index >= lobj.start and index < (lobj.start + lobj.dur):
|
247
|
-
_i = lobj.offset +
|
244
|
+
_i = round((lobj.offset + index - lobj.start) * lobj.speed)
|
248
245
|
obj_list.append(VideoFrame(_i, lobj.src))
|
249
246
|
elif index >= lobj.start and index < lobj.start + lobj.dur:
|
250
247
|
obj_list.append(lobj)
|
@@ -7,6 +7,7 @@ from typing import Any, Literal, TypedDict
|
|
7
7
|
|
8
8
|
from auto_editor.ffwrapper import initFileInfo
|
9
9
|
from auto_editor.lang.json import dump
|
10
|
+
from auto_editor.make_layers import make_sane_timebase
|
10
11
|
from auto_editor.timeline import v3
|
11
12
|
from auto_editor.utils.func import aspect_ratio
|
12
13
|
from auto_editor.utils.log import Log
|
@@ -68,6 +69,7 @@ class MediaJson(TypedDict, total=False):
|
|
68
69
|
subtitle: list[SubtitleJson]
|
69
70
|
container: ContainerJson
|
70
71
|
type: Literal["media", "timeline", "unknown"]
|
72
|
+
recommendedTimebase: str
|
71
73
|
version: Literal["v1", "v3"]
|
72
74
|
clips: int
|
73
75
|
|
@@ -108,6 +110,7 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
108
110
|
|
109
111
|
file_info[file] = {
|
110
112
|
"type": "media",
|
113
|
+
"recommendedTimebase": "30/1",
|
111
114
|
"video": [],
|
112
115
|
"audio": [],
|
113
116
|
"subtitle": [],
|
@@ -117,6 +120,12 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
117
120
|
},
|
118
121
|
}
|
119
122
|
|
123
|
+
if src.videos:
|
124
|
+
recTb = make_sane_timebase(src.videos[0].fps)
|
125
|
+
file_info[file]["recommendedTimebase"] = (
|
126
|
+
f"{recTb.numerator}/{recTb.denominator}"
|
127
|
+
)
|
128
|
+
|
120
129
|
for track, v in enumerate(src.videos):
|
121
130
|
w, h = v.width, v.height
|
122
131
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import sys
|
2
2
|
|
3
3
|
import av
|
4
|
-
from av.subtitles.subtitle import
|
4
|
+
from av.subtitles.subtitle import AssSubtitle, TextSubtitle
|
5
5
|
|
6
6
|
|
7
7
|
def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
@@ -10,12 +10,12 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
|
10
10
|
for s in range(len(container.streams.subtitles)):
|
11
11
|
print(f"file: {input_file} ({s}:{container.streams.subtitles[s].name})")
|
12
12
|
for packet in container.demux(subtitles=s):
|
13
|
-
for
|
14
|
-
|
15
|
-
if
|
16
|
-
print(
|
17
|
-
elif
|
18
|
-
print(
|
13
|
+
for subset in packet.decode():
|
14
|
+
for sub in subset.rects:
|
15
|
+
if isinstance(sub, AssSubtitle):
|
16
|
+
print(sub.ass.decode("utf-8", errors="ignore"))
|
17
|
+
elif isinstance(sub, TextSubtitle):
|
18
|
+
print(sub.text.decode("utf-8", errors="ignore"))
|
19
19
|
print("------")
|
20
20
|
|
21
21
|
|
@@ -67,9 +67,9 @@ class Bar:
|
|
67
67
|
|
68
68
|
if self.machine:
|
69
69
|
index = min(index, self.total)
|
70
|
-
|
70
|
+
secs_til_eta = round(self.begin_time + rate - time(), 2)
|
71
71
|
print(
|
72
|
-
f"{self.title}~{index}~{self.total}~{
|
72
|
+
f"{self.title}~{index}~{self.total}~{secs_til_eta}",
|
73
73
|
end="\r",
|
74
74
|
flush=True,
|
75
75
|
)
|
@@ -53,7 +53,7 @@ hevc_en = ["hevc", "libx265", "hevc_videotoolbox", "hevc_amf", "hevc_nvenc", "he
|
|
53
53
|
av1_en = ["av1", "libaom-av1", "av1_nvenc", "av1_amf"]
|
54
54
|
prores_en = ["prores", "prores_videotoolbox", "prores_aw", "prores_ks"]
|
55
55
|
aac_en = ["aac", "aac_at", "libfdk_aac"]
|
56
|
-
|
56
|
+
opus_en = ["opus", "libopus"]
|
57
57
|
|
58
58
|
h265: DictContainer = {
|
59
59
|
"allow_video": True,
|
@@ -80,7 +80,7 @@ mp4: DictContainer = {
|
|
80
80
|
"allow_subtitle": True,
|
81
81
|
"allow_image": True,
|
82
82
|
"vcodecs": h264_en + hevc_en + av1_en + ["vp9", "mpeg4", "mpeg2video", "mjpeg"],
|
83
|
-
"acodecs": aac_en + ["mp3", "
|
83
|
+
"acodecs": aac_en + opus_en + ["mp3", "flac", "vorbis", "libvorbis", "ac3", "mp2"],
|
84
84
|
"vstrict": True,
|
85
85
|
}
|
86
86
|
ogg: DictContainer = {
|
@@ -88,16 +88,16 @@ ogg: DictContainer = {
|
|
88
88
|
"allow_audio": True,
|
89
89
|
"allow_subtitle": True,
|
90
90
|
"vcodecs": ["libtheora", "theora"],
|
91
|
-
"acodecs": ["libvorbis", "vorbis", "flac", "
|
91
|
+
"acodecs": opus_en + ["libvorbis", "vorbis", "flac", "speex"],
|
92
92
|
"vstrict": True,
|
93
93
|
}
|
94
94
|
|
95
95
|
mka_audio = (
|
96
96
|
["libvorbis", "vorbis"]
|
97
97
|
+ aac_en
|
98
|
+
+ opus_en
|
98
99
|
+ [
|
99
100
|
"mp3",
|
100
|
-
"opus",
|
101
101
|
"flac",
|
102
102
|
"ac3",
|
103
103
|
"mp2",
|
@@ -172,11 +172,11 @@ containers: dict[str, DictContainer] = {
|
|
172
172
|
},
|
173
173
|
"opus": {
|
174
174
|
"allow_audio": True,
|
175
|
-
"acodecs": ["
|
175
|
+
"acodecs": opus_en + ["flac", "libvorbis", "vorbis", "speex"],
|
176
176
|
},
|
177
177
|
"oga": {
|
178
178
|
"allow_audio": True,
|
179
|
-
"acodecs": ["flac", "libvorbis", "vorbis", "
|
179
|
+
"acodecs": opus_en + ["flac", "libvorbis", "vorbis", "speex"],
|
180
180
|
},
|
181
181
|
"flac": {
|
182
182
|
"allow_audio": True,
|
@@ -188,7 +188,7 @@ containers: dict[str, DictContainer] = {
|
|
188
188
|
"allow_audio": True,
|
189
189
|
"allow_subtitle": True,
|
190
190
|
"vcodecs": ["vp9", "vp8"] + av1_en,
|
191
|
-
"acodecs": ["
|
191
|
+
"acodecs": opus_en + ["vorbis", "libvorbis"],
|
192
192
|
"scodecs": ["webvtt"],
|
193
193
|
"vstrict": True,
|
194
194
|
"sstrict": True,
|
@@ -24,7 +24,7 @@ class Timer:
|
|
24
24
|
|
25
25
|
|
26
26
|
class Log:
|
27
|
-
__slots__ = ("is_debug", "quiet", "temp")
|
27
|
+
__slots__ = ("is_debug", "quiet", "temp", "machine")
|
28
28
|
|
29
29
|
def __init__(
|
30
30
|
self, show_debug: bool = False, quiet: bool = False, temp: str | None = None
|
@@ -32,6 +32,7 @@ class Log:
|
|
32
32
|
self.is_debug = show_debug
|
33
33
|
self.quiet = quiet
|
34
34
|
self.temp = temp
|
35
|
+
self.machine = False
|
35
36
|
|
36
37
|
def debug(self, message: object) -> None:
|
37
38
|
if self.is_debug:
|
@@ -55,7 +56,9 @@ class Log:
|
|
55
56
|
self.debug(f"Failed to delete temp dir:\n{e}")
|
56
57
|
|
57
58
|
def conwrite(self, message: str) -> None:
|
58
|
-
if
|
59
|
+
if self.machine:
|
60
|
+
print(message, flush=True)
|
61
|
+
elif not self.quiet:
|
59
62
|
buffer = " " * (get_terminal_size().columns - len(message) - 3)
|
60
63
|
sys.stdout.write(f" {message}{buffer}\r")
|
61
64
|
|
@@ -164,8 +164,9 @@ def margin(val: str) -> tuple[str, str]:
|
|
164
164
|
return vals[0], vals[1]
|
165
165
|
|
166
166
|
|
167
|
-
def time_range(val: str) ->
|
168
|
-
|
167
|
+
def time_range(val: str) -> tuple[str, str]:
|
168
|
+
a = _comma_coerce("time_range", val, 2)
|
169
|
+
return a[0], a[1]
|
169
170
|
|
170
171
|
|
171
172
|
def speed_range(val: str) -> tuple[float, str, str]:
|
@@ -231,8 +232,8 @@ class Args:
|
|
231
232
|
extras: str | None = None
|
232
233
|
sn: bool = False
|
233
234
|
no_seek: bool = False
|
234
|
-
cut_out: list[
|
235
|
-
add_in: list[
|
235
|
+
cut_out: list[tuple[str, str]] = field(default_factory=list)
|
236
|
+
add_in: list[tuple[str, str]] = field(default_factory=list)
|
236
237
|
set_speed_for_range: list[tuple[float, str, str]] = field(default_factory=list)
|
237
238
|
frame_rate: Fraction | None = None
|
238
239
|
sample_rate: int | None = None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: auto-editor
|
3
|
-
Version: 24.
|
3
|
+
Version: 24.24.1
|
4
4
|
Summary: Auto-Editor: Effort free video editing!
|
5
5
|
Author-email: WyattBlue <wyattblue@auto-editor.com>
|
6
6
|
License: Unlicense
|
@@ -12,7 +12,7 @@ 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
|
15
|
+
Requires-Dist: pyav==12.1.0
|
16
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>
|
@@ -60,10 +60,10 @@ The `--edit` option is how auto-editor makes automated cuts.
|
|
60
60
|
For example, edit out motionlessness in a video by setting `--edit motion`.
|
61
61
|
|
62
62
|
```
|
63
|
-
# cut out sections where
|
64
|
-
auto-editor example.mp4 --edit motion:threshold=
|
63
|
+
# cut out sections where the total motion is less than 2%.
|
64
|
+
auto-editor example.mp4 --edit motion:threshold=0.02
|
65
65
|
|
66
|
-
#
|
66
|
+
# `--edit audio:threshold=0.04,stream=all` is used by defaut.
|
67
67
|
auto-editor example.mp4
|
68
68
|
|
69
69
|
# Different tracks can be set with different attribute.
|
@@ -73,34 +73,14 @@ auto-editor multi-track.mov --edit "(or audio:stream=0 audio:threshold=10%,strea
|
|
73
73
|
Different editing methods can be used together.
|
74
74
|
```
|
75
75
|
# 'threshold' is always the first argument for edit-method objects
|
76
|
-
auto-editor example.mp4 --edit "(or audio:
|
76
|
+
auto-editor example.mp4 --edit "(or audio:0.03 motion:0.06)"
|
77
77
|
```
|
78
78
|
|
79
79
|
You can also use `dB` unit, a volume unit familiar to video-editors (case sensitive):
|
80
80
|
```
|
81
|
-
auto-editor example.mp4 --edit audio
|
81
|
+
auto-editor example.mp4 --edit audio:-19dB
|
82
82
|
auto-editor example.mp4 --edit audio:-7dB
|
83
83
|
auto-editor example.mp4 --edit motion:-19dB
|
84
|
-
|
85
|
-
# The `dB` unit is a just a macro that expands into an S-expression:
|
86
|
-
# '-19dB
|
87
|
-
# > '(pow 10 (/ -19 20))
|
88
|
-
# (eval '(pow 10 (/ -19 20)))
|
89
|
-
# > 0.11220184543019636
|
90
|
-
```
|
91
|
-
|
92
|
-
### Working With Multiple Audio Tracks
|
93
|
-
By default, only the first audio track will used for editing (track 0). You can change this with these commands.
|
94
|
-
|
95
|
-
Use all audio tracks for editing:
|
96
|
-
```
|
97
|
-
auto-editor multi-track.mov --edit audio:stream=all
|
98
|
-
```
|
99
|
-
|
100
|
-
Use only the second, fourth, and sixth audio track:
|
101
|
-
```
|
102
|
-
# track numbers start at 0
|
103
|
-
auto-editor so-many-tracks.mp4 --edit "(or audio:stream=1 audio:stream=3 audio:stream=5)"
|
104
84
|
```
|
105
85
|
|
106
86
|
### See What Auto-Editor Cuts Out
|
@@ -119,12 +99,10 @@ auto-editor example.mp4 --export premiere
|
|
119
99
|
```
|
120
100
|
|
121
101
|
Auto-Editor can also export to:
|
122
|
-
|
123
102
|
- DaVinci Resolve with `--export resolve`
|
124
103
|
- Final Cut Pro with `--export final-cut-pro`
|
125
104
|
- ShotCut with `--export shotcut`
|
126
|
-
|
127
|
-
Other editors, like Sony Vegas, can understand the `premiere` format. If your favorite editor doesn't, you can use ` --export clip-sequence` which creates many video clips that can be imported and manipulated like normal.
|
105
|
+
- Individual media clips with `--export clip-sequence`
|
128
106
|
|
129
107
|
### Naming Timelines
|
130
108
|
By default, auto-editor will name the timeline to "Auto-Editor Media Group" if the export supports naming.
|
@@ -188,14 +166,11 @@ List all available options:
|
|
188
166
|
auto-editor --help
|
189
167
|
```
|
190
168
|
|
191
|
-
Use `--help` with a specific option
|
169
|
+
Use `--help` with a specific option to learn more about it:
|
192
170
|
|
193
171
|
```
|
194
|
-
auto-editor
|
195
|
-
|
196
|
-
|
197
|
-
default: 1.0
|
198
|
-
Scale the output video's resolution by NUM factor
|
172
|
+
auto-editor -c:v --help
|
173
|
+
auto-editor --margin --help
|
199
174
|
```
|
200
175
|
|
201
176
|
<h3 align="center">Auto-Editor is available on all major platforms</h3>
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|