|
1 | 1 | from __future__ import annotations
|
2 | 2 |
|
| 3 | +import math |
3 | 4 | import sys
|
4 | 5 | from dataclasses import dataclass, field
|
| 6 | +from fractions import Fraction |
5 | 7 | from typing import TYPE_CHECKING
|
6 | 8 |
|
| 9 | +import av |
7 | 10 | import numpy as np
|
| 11 | +from av.audio.fifo import AudioFifo |
8 | 12 |
|
9 | 13 | from auto_editor.analyze import LevelError, Levels
|
10 | 14 | from auto_editor.ffwrapper import FFmpeg, initFileInfo
|
@@ -80,23 +84,45 @@ def print_arr(arr: NDArray) -> None:
|
80 | 84 | print("")
|
81 | 85 |
|
82 | 86 |
|
83 |
| -def print_arr_gen(arr: Iterator[int | float | bool]) -> None: |
| 87 | +def print_arr_gen(arr: Iterator[int | float]) -> None: |
84 | 88 | print("")
|
85 | 89 | print("@start")
|
86 | 90 | for a in arr:
|
87 | 91 | if isinstance(a, float):
|
88 | 92 | print(f"{a:.20f}")
|
89 |
| - if isinstance(a, bool): |
90 |
| - print("1" if a else "0") |
91 |
| - if isinstance(a, int): |
| 93 | + else: |
92 | 94 | print(a)
|
93 | 95 | print("")
|
94 | 96 |
|
95 | 97 |
|
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 |
98 | 114 |
|
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") |
100 | 126 |
|
101 | 127 | video = container.streams.video[stream]
|
102 | 128 | video.thread_type = "AUTO"
|
@@ -197,7 +223,8 @@ def main(sys_args: list[str] = sys.argv[1:]) -> None:
|
197 | 223 | levels = Levels(ensure, src, tb, bar, temp, log)
|
198 | 224 | try:
|
199 | 225 | if method == "audio":
|
200 |
| - print_arr(levels.audio(**obj)) |
| 226 | + # print_arr(levels.audio(**obj)) |
| 227 | + print_arr_gen(iter_audio(src, tb, **obj)) |
201 | 228 | elif method == "motion":
|
202 | 229 | print_arr_gen(iter_motion(src, tb, **obj))
|
203 | 230 | elif method == "subtitle":
|
|
0 commit comments