auto-editor 27.0.0__py3-none-any.whl → 27.1.0__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.
- auto_editor/__init__.py +1 -1
- auto_editor/__main__.py +8 -0
- auto_editor/cmds/desc.py +2 -2
- auto_editor/cmds/info.py +2 -2
- auto_editor/cmds/levels.py +2 -2
- auto_editor/cmds/repl.py +3 -8
- auto_editor/cmds/test.py +36 -2
- auto_editor/edit.py +37 -79
- auto_editor/ffwrapper.py +88 -84
- auto_editor/formats/fcp11.py +10 -8
- auto_editor/formats/fcp7.py +11 -12
- auto_editor/formats/json.py +8 -9
- auto_editor/lang/stdenv.py +1 -0
- auto_editor/make_layers.py +18 -8
- auto_editor/render/audio.py +219 -84
- auto_editor/render/video.py +1 -2
- auto_editor/timeline.py +60 -10
- auto_editor/utils/container.py +19 -12
- auto_editor/utils/func.py +21 -0
- {auto_editor-27.0.0.dist-info → auto_editor-27.1.0.dist-info}/METADATA +2 -2
- {auto_editor-27.0.0.dist-info → auto_editor-27.1.0.dist-info}/RECORD +25 -27
- {auto_editor-27.0.0.dist-info → auto_editor-27.1.0.dist-info}/WHEEL +1 -1
- auto_editor/output.py +0 -86
- auto_editor/wavfile.py +0 -310
- {auto_editor-27.0.0.dist-info → auto_editor-27.1.0.dist-info}/entry_points.txt +0 -0
- {auto_editor-27.0.0.dist-info → auto_editor-27.1.0.dist-info}/licenses/LICENSE +0 -0
- {auto_editor-27.0.0.dist-info → auto_editor-27.1.0.dist-info}/top_level.txt +0 -0
auto_editor/timeline.py
CHANGED
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
3
3
|
from dataclasses import dataclass
|
4
4
|
from typing import TYPE_CHECKING
|
5
5
|
|
6
|
-
from auto_editor.ffwrapper import
|
6
|
+
from auto_editor.ffwrapper import FileInfo, mux
|
7
7
|
from auto_editor.lib.contracts import *
|
8
8
|
from auto_editor.utils.cmdkw import Required, pAttr, pAttrs
|
9
9
|
from auto_editor.utils.types import CoerceError, natural, number, parse_color
|
@@ -187,13 +187,52 @@ ALayer = list[TlAudio]
|
|
187
187
|
ASpace = list[ALayer]
|
188
188
|
|
189
189
|
|
190
|
+
@dataclass(slots=True)
|
191
|
+
class AudioTemplate:
|
192
|
+
lang: str | None
|
193
|
+
|
194
|
+
|
195
|
+
@dataclass(slots=True)
|
196
|
+
class SubtitleTemplate:
|
197
|
+
lang: str | None
|
198
|
+
|
199
|
+
|
200
|
+
@dataclass(slots=True)
|
201
|
+
class Template:
|
202
|
+
sr: int
|
203
|
+
layout: str
|
204
|
+
res: tuple[int, int]
|
205
|
+
audios: list[AudioTemplate]
|
206
|
+
subtitles: list[SubtitleTemplate]
|
207
|
+
|
208
|
+
@classmethod
|
209
|
+
def init(
|
210
|
+
self,
|
211
|
+
src: FileInfo,
|
212
|
+
sr: int | None = None,
|
213
|
+
layout: str | None = None,
|
214
|
+
res: tuple[int, int] | None = None,
|
215
|
+
) -> Template:
|
216
|
+
alist = [AudioTemplate(x.lang) for x in src.audios]
|
217
|
+
slist = [SubtitleTemplate(x.lang) for x in src.subtitles]
|
218
|
+
|
219
|
+
if sr is None:
|
220
|
+
sr = src.get_sr()
|
221
|
+
|
222
|
+
if layout is None:
|
223
|
+
layout = "stereo" if not src.audios else src.audios[0].layout
|
224
|
+
|
225
|
+
if res is None:
|
226
|
+
res = src.get_res()
|
227
|
+
|
228
|
+
return Template(sr, layout, res, alist, slist)
|
229
|
+
|
230
|
+
|
190
231
|
@dataclass
|
191
232
|
class v3:
|
192
|
-
src: FileInfo | None # Used as a template for timeline settings
|
193
233
|
tb: Fraction
|
194
|
-
sr: int
|
195
|
-
res: tuple[int, int]
|
196
234
|
background: str
|
235
|
+
template: Template
|
197
236
|
v: VSpace
|
198
237
|
a: ASpace
|
199
238
|
v1: v1 | None # Is it v1 compatible (linear and only one source)?
|
@@ -286,14 +325,27 @@ video\n"""
|
|
286
325
|
|
287
326
|
return {
|
288
327
|
"version": "3",
|
289
|
-
"resolution": self.res,
|
290
328
|
"timebase": f"{self.tb.numerator}/{self.tb.denominator}",
|
291
|
-
"samplerate": self.sr,
|
292
329
|
"background": self.background,
|
330
|
+
"resolution": self.T.res,
|
331
|
+
"samplerate": self.T.sr,
|
332
|
+
"layout": self.T.layout,
|
293
333
|
"v": v,
|
294
334
|
"a": a,
|
295
335
|
}
|
296
336
|
|
337
|
+
@property
|
338
|
+
def T(self) -> Template:
|
339
|
+
return self.template
|
340
|
+
|
341
|
+
@property
|
342
|
+
def res(self) -> tuple[int, int]:
|
343
|
+
return self.T.res
|
344
|
+
|
345
|
+
@property
|
346
|
+
def sr(self) -> int:
|
347
|
+
return self.T.sr
|
348
|
+
|
297
349
|
|
298
350
|
def make_tracks_dir(path: Path) -> Path:
|
299
351
|
from os import mkdir
|
@@ -310,9 +362,7 @@ def make_tracks_dir(path: Path) -> Path:
|
|
310
362
|
return tracks_dir
|
311
363
|
|
312
364
|
|
313
|
-
def set_stream_to_0(tl: v3, log: Log) -> None:
|
314
|
-
src = tl.src
|
315
|
-
assert src is not None
|
365
|
+
def set_stream_to_0(src: FileInfo, tl: v3, log: Log) -> None:
|
316
366
|
fold = make_tracks_dir(src.path)
|
317
367
|
cache: dict[Path, FileInfo] = {}
|
318
368
|
|
@@ -320,7 +370,7 @@ def set_stream_to_0(tl: v3, log: Log) -> None:
|
|
320
370
|
newtrack = fold / f"{path.stem}_{i}.wav"
|
321
371
|
if newtrack not in cache:
|
322
372
|
mux(path, output=newtrack, stream=i)
|
323
|
-
cache[newtrack] =
|
373
|
+
cache[newtrack] = FileInfo.init(f"{newtrack}", log)
|
324
374
|
return cache[newtrack]
|
325
375
|
|
326
376
|
for alayer in tl.a:
|
auto_editor/utils/container.py
CHANGED
@@ -6,6 +6,8 @@ from typing import TypedDict
|
|
6
6
|
import bv
|
7
7
|
from bv.codec import Codec
|
8
8
|
|
9
|
+
from auto_editor.utils.log import Log
|
10
|
+
|
9
11
|
|
10
12
|
class DictContainer(TypedDict, total=False):
|
11
13
|
max_videos: int | None
|
@@ -60,18 +62,23 @@ def codec_type(x: str) -> str:
|
|
60
62
|
return ""
|
61
63
|
|
62
64
|
|
63
|
-
def container_constructor(ext: str) -> Container:
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
65
|
+
def container_constructor(ext: str, log: Log) -> Container:
|
66
|
+
try:
|
67
|
+
container = bv.open(f".{ext}", "w")
|
68
|
+
except ValueError:
|
69
|
+
log.error(f"Could not find a suitable format for extension: {ext}")
|
70
|
+
|
71
|
+
codecs = container.supported_codecs
|
72
|
+
if ext == "webm":
|
73
|
+
vdefault = "vp9"
|
74
|
+
else:
|
75
|
+
vdefault = container.default_video_codec
|
76
|
+
adefault = container.default_audio_codec
|
77
|
+
sdefault = container.default_subtitle_codec
|
78
|
+
if sdefault == "none" and ext == "mp4":
|
79
|
+
sdefault = "srt"
|
80
|
+
|
81
|
+
container.close()
|
75
82
|
vcodecs = set()
|
76
83
|
acodecs = set()
|
77
84
|
scodecs = set()
|
auto_editor/utils/func.py
CHANGED
@@ -4,6 +4,9 @@ from typing import TYPE_CHECKING
|
|
4
4
|
|
5
5
|
import numpy as np
|
6
6
|
|
7
|
+
from auto_editor.utils.log import Log
|
8
|
+
from auto_editor.utils.types import split_num_str
|
9
|
+
|
7
10
|
if TYPE_CHECKING:
|
8
11
|
from collections.abc import Callable
|
9
12
|
from fractions import Fraction
|
@@ -105,3 +108,21 @@ def aspect_ratio(width: int, height: int) -> tuple[int, int]:
|
|
105
108
|
|
106
109
|
c = gcd(width, height)
|
107
110
|
return width // c, height // c
|
111
|
+
|
112
|
+
|
113
|
+
def parse_bitrate(input_: str, log: Log) -> int:
|
114
|
+
try:
|
115
|
+
val, unit = split_num_str(input_)
|
116
|
+
except Exception as e:
|
117
|
+
log.error(e)
|
118
|
+
|
119
|
+
if unit.lower() == "k":
|
120
|
+
return int(val * 1000)
|
121
|
+
if unit == "M":
|
122
|
+
return int(val * 1_000_000)
|
123
|
+
if unit == "G":
|
124
|
+
return int(val * 1_000_000_000)
|
125
|
+
if unit == "":
|
126
|
+
return int(val)
|
127
|
+
|
128
|
+
log.error(f"Unknown bitrate: {input_}")
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: auto-editor
|
3
|
-
Version: 27.
|
3
|
+
Version: 27.1.0
|
4
4
|
Summary: Auto-Editor: Effort free video editing!
|
5
5
|
Author-email: WyattBlue <wyattblue@auto-editor.com>
|
6
|
-
License: Unlicense
|
6
|
+
License-Expression: Unlicense
|
7
7
|
Project-URL: Bug Tracker, https://github.com/WyattBlue/auto-editor/issues
|
8
8
|
Project-URL: Source Code, https://github.com/WyattBlue/auto-editor
|
9
9
|
Project-URL: homepage, https://auto-editor.com
|
@@ -1,56 +1,54 @@
|
|
1
|
-
auto_editor/__init__.py,sha256=
|
2
|
-
auto_editor/__main__.py,sha256=
|
1
|
+
auto_editor/__init__.py,sha256=GyXI0pHyyPF89C9QtYg4zFjEDtSMUJMNUdrc74jh27A,23
|
2
|
+
auto_editor/__main__.py,sha256=WfNtjKwx5fDMPpfSNLarigXD3Jp0My98FpzQqSAxQZ8,15807
|
3
3
|
auto_editor/analyze.py,sha256=CeJG0LI9wXZk1R-QPrNGPS4za-_Avd8y7H-D437DqLg,12300
|
4
|
-
auto_editor/edit.py,sha256=
|
5
|
-
auto_editor/ffwrapper.py,sha256=
|
4
|
+
auto_editor/edit.py,sha256=UbKG5jhl5K3kCx9wIB_-Con6PF-4H0-Du0yVln3B5Qc,18921
|
5
|
+
auto_editor/ffwrapper.py,sha256=Wet6B5nohgnjpBX7o20Zq0rYr-H9mUuOqHrbQAPPj38,5128
|
6
6
|
auto_editor/help.py,sha256=CzfDTsL4GuGu596ySHKj_wKnxGR9h8B0KUdkZpo33oE,8044
|
7
7
|
auto_editor/json.py,sha256=8IVhZJSLx2IVqJsbR5YKDvbHOhgIOvdQmYNpMdMG_xA,9332
|
8
|
-
auto_editor/make_layers.py,sha256=
|
9
|
-
auto_editor/output.py,sha256=YgkZw0WyVfcTYH-4j6kYfvB6A1BjxGLmfOQVFi-QK_o,2561
|
8
|
+
auto_editor/make_layers.py,sha256=nSEeCHysMot2eze23q05g2HFDuskN_4Jk108xlk2Rw8,10102
|
10
9
|
auto_editor/preview.py,sha256=cqQdozM2IB-5qXHNxeqiSrSdEIzlMfjD4SU-NX9sYZ0,3052
|
11
|
-
auto_editor/timeline.py,sha256=
|
10
|
+
auto_editor/timeline.py,sha256=Ku6BdDDzdboO0DisO_KLDjAyxJLQVDybWVgFbGCcsmY,9416
|
12
11
|
auto_editor/vanparse.py,sha256=Ug5A2QaRqGiw4l55Z_h9T2QU1x0WqRibR7yY5rQ0WTk,10002
|
13
|
-
auto_editor/wavfile.py,sha256=afFfje8cK9lFjIkYoBbQHfvQIpsEPxWvspCtFhUKlAw,9499
|
14
12
|
auto_editor/cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
13
|
auto_editor/cmds/cache.py,sha256=bViYbtVXefTeEIUvSanDfA6cG35ep1N_Jvtz7ZjgIkY,1959
|
16
|
-
auto_editor/cmds/desc.py,sha256=
|
17
|
-
auto_editor/cmds/info.py,sha256=
|
18
|
-
auto_editor/cmds/levels.py,sha256=
|
14
|
+
auto_editor/cmds/desc.py,sha256=DSAWPKt8PS9soBTgzpsFIEWoTe4gPTWwjXpNL-p3WsI,866
|
15
|
+
auto_editor/cmds/info.py,sha256=VA2WkTBbQPvrVHjDaJyqryoVMtiiN6cguiUMdWgBJfU,7002
|
16
|
+
auto_editor/cmds/levels.py,sha256=2Hbvoy6wMbRRoHdZf25PMqq1uvhRKyPcITNPMpZFo7s,5632
|
19
17
|
auto_editor/cmds/palet.py,sha256=ONzTqemaQq9YEfIOsDRNnwzfqnEMUMSXIQrETxyroRU,749
|
20
|
-
auto_editor/cmds/repl.py,sha256=
|
18
|
+
auto_editor/cmds/repl.py,sha256=HSUTDaVykPb5Bd-v_jz_8R7HvFmKOcT_ZVmP-d0AbUY,3247
|
21
19
|
auto_editor/cmds/subdump.py,sha256=kHg8nfUi6I6VeJjEgMxupPa666qsYUh7ZEUxint7Gqo,2443
|
22
|
-
auto_editor/cmds/test.py,sha256=
|
20
|
+
auto_editor/cmds/test.py,sha256=UNN1r6J69-woqA6QU7TeY0WlPxukQzwCRl5DGBTLK8g,28837
|
23
21
|
auto_editor/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
|
-
auto_editor/formats/fcp11.py,sha256=
|
25
|
-
auto_editor/formats/fcp7.py,sha256=
|
26
|
-
auto_editor/formats/json.py,sha256=
|
22
|
+
auto_editor/formats/fcp11.py,sha256=uaJbLiwiVxqoVy5JCA14wZj-m1wqZIzWh7rS-BsnSQM,5219
|
23
|
+
auto_editor/formats/fcp7.py,sha256=rHjXXjpJ5YQQvCxor7FpUaqaAreqjCas4uLpiTdFclc,20255
|
24
|
+
auto_editor/formats/json.py,sha256=UUBhFR_79vn4Lxu73B0cVBFgw4qytrmMP-TiCmDFMd0,7666
|
27
25
|
auto_editor/formats/shotcut.py,sha256=-ES854LLFCMCBe100JRJedDmuk8zPev17aQMTrzPv-g,4923
|
28
26
|
auto_editor/formats/utils.py,sha256=LYXDiqOk9WwUorLGw2D0M7In9BNDkoKikNawuks7hqE,1648
|
29
27
|
auto_editor/lang/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
28
|
auto_editor/lang/libintrospection.py,sha256=6H1rGp0wqaCud5IPaoEmzULGnYt6ec7_0h32ATcw2oY,261
|
31
29
|
auto_editor/lang/libmath.py,sha256=z33A161Oe6vYYK7R6pgYjdZZe63dQkN38Qf36TL3prg,847
|
32
30
|
auto_editor/lang/palet.py,sha256=RQjyIZMJSWnzDkHTu-5mt74o9_4zO4VrcH-wLojCF7A,24113
|
33
|
-
auto_editor/lang/stdenv.py,sha256=
|
31
|
+
auto_editor/lang/stdenv.py,sha256=o7kFu7EbaH71XPFGxJUXYGxSeZ8O3i1_C5Hmi9uya4Q,44150
|
34
32
|
auto_editor/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
33
|
auto_editor/lib/contracts.py,sha256=lExGQymcQUmwG5lC1lO4qm4GY8W0q_yzK_miTaAoPA4,7586
|
36
34
|
auto_editor/lib/data_structs.py,sha256=Hnzl5gWvo-geTU0g-lGejj6HQW3VvPv0NBEj2XoGskY,7089
|
37
35
|
auto_editor/lib/err.py,sha256=UlszQJdzMZwkbT8x3sY4GkCV_5x9yrd6uVVUzvA8iiI,35
|
38
36
|
auto_editor/render/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
|
-
auto_editor/render/audio.py,sha256=
|
37
|
+
auto_editor/render/audio.py,sha256=ejV_NIvrmxMJt6mf7nPNIzlPHOumNhcIO2J-irHO-k8,17427
|
40
38
|
auto_editor/render/subtitle.py,sha256=F27T8OsAojUIGTGBWqTdH36h0BnHXSExxIqzOtqyZoE,6129
|
41
|
-
auto_editor/render/video.py,sha256=
|
39
|
+
auto_editor/render/video.py,sha256=uIrYzF4bDZ3vwfX2F6TdR6F73GI4yruGssto9xEQ-AA,11999
|
42
40
|
auto_editor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
43
41
|
auto_editor/utils/bar.py,sha256=Ky9JRf37JTgLyvNuIXDfucaUE8H1vBbCqKLjttmsmmo,4156
|
44
42
|
auto_editor/utils/chunks.py,sha256=J-eGKtEz68gFtRrj1kOSgH4Tj_Yz6prNQ7Xr-d9NQJw,52
|
45
43
|
auto_editor/utils/cmdkw.py,sha256=aUGBvBel2Ko1o6Rwmr4rEL-BMc5hEnzYLbyZ1GeJdcY,5729
|
46
|
-
auto_editor/utils/container.py,sha256=
|
47
|
-
auto_editor/utils/func.py,sha256=
|
44
|
+
auto_editor/utils/container.py,sha256=CNHChHbhzIrjmDdWw6UzMqscrr9u7A-ZqKWejGjJwYE,2628
|
45
|
+
auto_editor/utils/func.py,sha256=ODyjXnzSDatEu08w398K8_xBKYdXMY3IPHiJpGRZDyQ,3250
|
48
46
|
auto_editor/utils/log.py,sha256=wPNf6AabV-0cnoS_bPLv1Lh7llQBtNqPKeh07einOuc,3701
|
49
47
|
auto_editor/utils/types.py,sha256=j2hd4zMQ9EftDy41Ji2_PFru_7HEZObd9yKA0BJxFaY,7616
|
50
|
-
auto_editor-27.
|
48
|
+
auto_editor-27.1.0.dist-info/licenses/LICENSE,sha256=yiq99pWITHfqS0pbZMp7cy2dnbreTuvBwudsU-njvIM,1210
|
51
49
|
docs/build.py,sha256=g1uc1H9T_naGaermUiVMMwUpbT0IWElRhjgT0fvCh8w,1914
|
52
|
-
auto_editor-27.
|
53
|
-
auto_editor-27.
|
54
|
-
auto_editor-27.
|
55
|
-
auto_editor-27.
|
56
|
-
auto_editor-27.
|
50
|
+
auto_editor-27.1.0.dist-info/METADATA,sha256=JU6SgcQLr3thOG27aQRkt2r3INzU0q306BeK79qkwGs,6176
|
51
|
+
auto_editor-27.1.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
52
|
+
auto_editor-27.1.0.dist-info/entry_points.txt,sha256=UAsTc7qJQbnAzHd7KWg-ALo_X9Hj2yDs3M9I2DV3eyI,212
|
53
|
+
auto_editor-27.1.0.dist-info/top_level.txt,sha256=jBV5zlbWRbKOa-xaWPvTD45QL7lGExx2BDzv-Ji4dTw,17
|
54
|
+
auto_editor-27.1.0.dist-info/RECORD,,
|
auto_editor/output.py
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import os.path
|
4
|
-
from dataclasses import dataclass, field
|
5
|
-
|
6
|
-
import bv
|
7
|
-
from bv.audio.resampler import AudioResampler
|
8
|
-
|
9
|
-
from auto_editor.ffwrapper import FileInfo
|
10
|
-
from auto_editor.utils.bar import Bar
|
11
|
-
from auto_editor.utils.log import Log
|
12
|
-
from auto_editor.utils.types import split_num_str
|
13
|
-
|
14
|
-
|
15
|
-
def parse_bitrate(input_: str, log: Log) -> int:
|
16
|
-
try:
|
17
|
-
val, unit = split_num_str(input_)
|
18
|
-
except Exception as e:
|
19
|
-
log.error(e)
|
20
|
-
|
21
|
-
if unit.lower() == "k":
|
22
|
-
return int(val * 1000)
|
23
|
-
if unit == "M":
|
24
|
-
return int(val * 1_000_000)
|
25
|
-
if unit == "G":
|
26
|
-
return int(val * 1_000_000_000)
|
27
|
-
if unit == "":
|
28
|
-
return int(val)
|
29
|
-
|
30
|
-
log.error(f"Unknown bitrate: {input_}")
|
31
|
-
|
32
|
-
|
33
|
-
@dataclass(slots=True)
|
34
|
-
class Ensure:
|
35
|
-
_bar: Bar
|
36
|
-
_sr: int
|
37
|
-
log: Log
|
38
|
-
_audios: list[tuple[FileInfo, int]] = field(default_factory=list)
|
39
|
-
|
40
|
-
def audio(self, src: FileInfo, stream: int) -> str:
|
41
|
-
try:
|
42
|
-
label = self._audios.index((src, stream))
|
43
|
-
first_time = False
|
44
|
-
except ValueError:
|
45
|
-
self._audios.append((src, stream))
|
46
|
-
label = len(self._audios) - 1
|
47
|
-
first_time = True
|
48
|
-
|
49
|
-
out_path = os.path.join(self.log.temp, f"{label:x}.wav")
|
50
|
-
|
51
|
-
if first_time:
|
52
|
-
sample_rate = self._sr
|
53
|
-
bar = self._bar
|
54
|
-
self.log.debug(f"Making external audio: {out_path}")
|
55
|
-
|
56
|
-
in_container = bv.open(src.path, "r")
|
57
|
-
out_container = bv.open(
|
58
|
-
out_path, "w", format="wav", options={"rf64": "always"}
|
59
|
-
)
|
60
|
-
astream = in_container.streams.audio[stream]
|
61
|
-
|
62
|
-
if astream.duration is None or astream.time_base is None:
|
63
|
-
dur = 1.0
|
64
|
-
else:
|
65
|
-
dur = float(astream.duration * astream.time_base)
|
66
|
-
|
67
|
-
bar.start(dur, "Extracting audio")
|
68
|
-
|
69
|
-
output_astream = out_container.add_stream(
|
70
|
-
"pcm_s16le", layout="stereo", rate=sample_rate
|
71
|
-
)
|
72
|
-
resampler = AudioResampler(format="s16", layout="stereo", rate=sample_rate)
|
73
|
-
for i, frame in enumerate(in_container.decode(astream)):
|
74
|
-
if i % 1500 == 0 and frame.time is not None:
|
75
|
-
bar.tick(frame.time)
|
76
|
-
|
77
|
-
for new_frame in resampler.resample(frame):
|
78
|
-
out_container.mux(output_astream.encode(new_frame))
|
79
|
-
|
80
|
-
out_container.mux(output_astream.encode(None))
|
81
|
-
|
82
|
-
out_container.close()
|
83
|
-
in_container.close()
|
84
|
-
bar.end()
|
85
|
-
|
86
|
-
return out_path
|