Skip to content

Commit 1e96fa4

Browse files
committed
Use a 1-pass audio method for levels
1 parent 944be41 commit 1e96fa4

File tree

1 file changed

+35
-8
lines changed

1 file changed

+35
-8
lines changed

auto_editor/subcommands/levels.py

+35-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
from __future__ import annotations
22

3+
import math
34
import sys
45
from dataclasses import dataclass, field
6+
from fractions import Fraction
57
from typing import TYPE_CHECKING
68

9+
import av
710
import numpy as np
11+
from av.audio.fifo import AudioFifo
812

913
from auto_editor.analyze import LevelError, Levels
1014
from auto_editor.ffwrapper import FFmpeg, initFileInfo
@@ -80,23 +84,45 @@ def print_arr(arr: NDArray) -> None:
8084
print("")
8185

8286

83-
def print_arr_gen(arr: Iterator[int | float | bool]) -> None:
87+
def print_arr_gen(arr: Iterator[int | float]) -> None:
8488
print("")
8589
print("@start")
8690
for a in arr:
8791
if isinstance(a, float):
8892
print(f"{a:.20f}")
89-
if isinstance(a, bool):
90-
print("1" if a else "0")
91-
if isinstance(a, int):
93+
else:
9294
print(a)
9395
print("")
9496

9597

96-
def iter_motion(src, tb, stream: int, blur: int, width: int) -> Iterator[float]:
97-
import av
98+
def iter_audio(src, tb: Fraction, stream: int = 0) -> Iterator[float]:
99+
fifo = AudioFifo()
100+
try:
101+
container = av.open(src.path, "r")
102+
sample_rate = container.streams.audio[stream].rate
103+
104+
exact_size = (1 / tb) * sample_rate
105+
accumulated_error = 0
106+
107+
for frame in container.decode(audio=stream):
108+
fifo.write(frame)
109+
110+
while fifo.samples >= math.ceil(exact_size):
111+
size_with_error = exact_size + accumulated_error
112+
current_size = round(size_with_error)
113+
accumulated_error = size_with_error - current_size
98114

99-
container = av.open(f"{src.path}", "r")
115+
audio_chunk = fifo.read(current_size)
116+
assert audio_chunk is not None
117+
arr = audio_chunk.to_ndarray().flatten()
118+
yield float(np.max(np.abs(arr)))
119+
120+
finally:
121+
container.close()
122+
123+
124+
def iter_motion(src, tb, stream: int, blur: int, width: int) -> Iterator[float]:
125+
container = av.open(src.path, "r")
100126

101127
video = container.streams.video[stream]
102128
video.thread_type = "AUTO"
@@ -197,7 +223,8 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
197223
levels = Levels(ensure, src, tb, bar, temp, log)
198224
try:
199225
if method == "audio":
200-
print_arr(levels.audio(**obj))
226+
# print_arr(levels.audio(**obj))
227+
print_arr_gen(iter_audio(src, tb, **obj))
201228
elif method == "motion":
202229
print_arr_gen(iter_motion(src, tb, **obj))
203230
elif method == "subtitle":

0 commit comments

Comments
 (0)