ffmpeg-normalize 1.42.0__tar.gz → 1.43.0__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.
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/PKG-INFO +8 -2
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/README.md +6 -1
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/pyproject.toml +2 -1
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/pyproject.toml.orig +2 -1
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/__main__.py +18 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/_ffmpeg_normalize.py +99 -1
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/_media_file.py +22 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/_streams.py +90 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/LICENSE.md +0 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/__init__.py +0 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/_cmd_utils.py +0 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/_errors.py +0 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/_logger.py +0 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/_presets.py +0 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/data/presets/music.json +0 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/data/presets/podcast.json +0 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/data/presets/streaming-video.json +0 -0
- {ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ffmpeg-normalize
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.43.0
|
|
4
4
|
Summary: Normalize audio via ffmpeg
|
|
5
5
|
Keywords: ffmpeg,normalize,audio
|
|
6
6
|
Author: Werner Robitza
|
|
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.13
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
22
23
|
Requires-Dist: tqdm>=4.64.1
|
|
23
24
|
Requires-Dist: colorama>=0.4.6 ; sys_platform == 'win32'
|
|
24
25
|
Requires-Dist: ffmpeg-progress-yield>=1.0.1
|
|
@@ -29,7 +30,11 @@ Project-URL: Homepage, https://github.com/slhck/ffmpeg-normalize
|
|
|
29
30
|
Project-URL: Repository, https://github.com/slhck/ffmpeg-normalize
|
|
30
31
|
Description-Content-Type: text/markdown
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
<h1 align="center">ffmpeg-normalize</h1>
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
<img src="icon.png" alt="ffmpeg-normalize logo" width="160" height="160">
|
|
37
|
+
</p>
|
|
33
38
|
|
|
34
39
|
[](https://pypi.org/project/ffmpeg-normalize)
|
|
35
40
|
[](https://hub.docker.com/r/slhck/ffmpeg-normalize)
|
|
@@ -50,6 +55,7 @@ This program normalizes media files to a certain loudness level using the EBU R1
|
|
|
50
55
|
- Peak normalization — Adjust audio to a specific peak level
|
|
51
56
|
- Selective audio stream normalization — Normalize specific audio streams or only default streams
|
|
52
57
|
- Skip files already at target — Avoid re-encoding files already within a threshold of the target level
|
|
58
|
+
- Before/after summary — Print a table of input and output levels and the applied gain for all files with `--print-summary`
|
|
53
59
|
- Self-documenting output — Optionally record the effective encoder settings as an `ENCODER_SETTINGS` tag
|
|
54
60
|
- Video file support — Process video files while preserving video streams
|
|
55
61
|
- Docker support — Run via Docker container
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<h1 align="center">ffmpeg-normalize</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="icon.png" alt="ffmpeg-normalize logo" width="160" height="160">
|
|
5
|
+
</p>
|
|
2
6
|
|
|
3
7
|
[](https://pypi.org/project/ffmpeg-normalize)
|
|
4
8
|
[](https://hub.docker.com/r/slhck/ffmpeg-normalize)
|
|
@@ -19,6 +23,7 @@ This program normalizes media files to a certain loudness level using the EBU R1
|
|
|
19
23
|
- Peak normalization — Adjust audio to a specific peak level
|
|
20
24
|
- Selective audio stream normalization — Normalize specific audio streams or only default streams
|
|
21
25
|
- Skip files already at target — Avoid re-encoding files already within a threshold of the target level
|
|
26
|
+
- Before/after summary — Print a table of input and output levels and the applied gain for all files with `--print-summary`
|
|
22
27
|
- Self-documenting output — Optionally record the effective encoder settings as an `ENCODER_SETTINGS` tag
|
|
23
28
|
- Video file support — Process video files while preserving video streams
|
|
24
29
|
- Docker support — Run via Docker container
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ffmpeg-normalize"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.43.0"
|
|
8
8
|
description = "Normalize audio via ffmpeg"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -27,6 +27,7 @@ classifiers = [
|
|
|
27
27
|
"Programming Language :: Python :: 3.12",
|
|
28
28
|
"Programming Language :: Python :: 3.13",
|
|
29
29
|
"Programming Language :: Python :: 3.14",
|
|
30
|
+
"Programming Language :: Python :: 3.15",
|
|
30
31
|
]
|
|
31
32
|
requires-python = ">=3.10"
|
|
32
33
|
dependencies = [
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ffmpeg-normalize"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.43.0"
|
|
8
8
|
description = "Normalize audio via ffmpeg"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -26,6 +26,7 @@ classifiers = [
|
|
|
26
26
|
"Programming Language :: Python :: 3.12",
|
|
27
27
|
"Programming Language :: Python :: 3.13",
|
|
28
28
|
"Programming Language :: Python :: 3.14",
|
|
29
|
+
"Programming Language :: Python :: 3.15",
|
|
29
30
|
]
|
|
30
31
|
requires-python = ">=3.10"
|
|
31
32
|
dependencies = [
|
|
@@ -204,6 +204,23 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
204
204
|
action="store_true",
|
|
205
205
|
help="Print loudness statistics for both passes formatted as JSON to stdout.",
|
|
206
206
|
)
|
|
207
|
+
group_normalization.add_argument(
|
|
208
|
+
"--print-summary",
|
|
209
|
+
action="store_true",
|
|
210
|
+
help=textwrap.dedent(
|
|
211
|
+
"""\
|
|
212
|
+
Print a before/after summary table to stderr after processing.
|
|
213
|
+
|
|
214
|
+
For each file and audio stream, the table lists the input level, the
|
|
215
|
+
output level, the output peak, the applied gain, and the status. The
|
|
216
|
+
level is the integrated loudness for EBU, the RMS level for RMS, and the
|
|
217
|
+
peak level for peak normalization. Values that are not available are
|
|
218
|
+
shown as `-`.
|
|
219
|
+
|
|
220
|
+
Can be combined with `--print-stats`, which writes JSON to stdout.
|
|
221
|
+
"""
|
|
222
|
+
),
|
|
223
|
+
)
|
|
207
224
|
group_normalization.add_argument(
|
|
208
225
|
"--replaygain",
|
|
209
226
|
action="store_true",
|
|
@@ -739,6 +756,7 @@ def main() -> None:
|
|
|
739
756
|
normalization_type=cli_args.normalization_type,
|
|
740
757
|
target_level=cli_args.target_level,
|
|
741
758
|
print_stats=cli_args.print_stats,
|
|
759
|
+
print_summary=cli_args.print_summary,
|
|
742
760
|
threshold=cli_args.threshold,
|
|
743
761
|
loudness_range_target=cli_args.loudness_range_target,
|
|
744
762
|
keep_loudness_range_target=cli_args.keep_loudness_range_target,
|
{ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/_ffmpeg_normalize.py
RENAMED
|
@@ -21,7 +21,7 @@ from ._errors import FFmpegNormalizeError
|
|
|
21
21
|
from ._media_file import MediaFile
|
|
22
22
|
|
|
23
23
|
if TYPE_CHECKING:
|
|
24
|
-
from ._streams import LoudnessStatisticsWithMetadata
|
|
24
|
+
from ._streams import LoudnessStatisticsWithMetadata, SummaryRow
|
|
25
25
|
|
|
26
26
|
_logger = logging.getLogger(__name__)
|
|
27
27
|
|
|
@@ -60,6 +60,7 @@ class FFmpegNormalize:
|
|
|
60
60
|
normalization_type (str, optional): Normalization type. Defaults to "ebu".
|
|
61
61
|
target_level (float, optional): Target level. Defaults to -23.0.
|
|
62
62
|
print_stats (bool, optional): Print loudnorm stats. Defaults to False.
|
|
63
|
+
print_summary (bool, optional): Print a before/after summary table to stderr after processing. Defaults to False.
|
|
63
64
|
threshold (float, optional): When set to a positive value, skip normalization when the input is already within this many dB/LU of the target level, copying it through unchanged. Defaults to 0 (disabled, always normalize).
|
|
64
65
|
loudness_range_target (float, optional): Loudness range target. Defaults to 7.0.
|
|
65
66
|
keep_loudness_range_target (bool, optional): Keep loudness range target. Defaults to False.
|
|
@@ -108,6 +109,7 @@ class FFmpegNormalize:
|
|
|
108
109
|
"normalization_type": "ebu",
|
|
109
110
|
"target_level": -23.0,
|
|
110
111
|
"print_stats": False,
|
|
112
|
+
"print_summary": False,
|
|
111
113
|
"threshold": 0.0,
|
|
112
114
|
"loudness_range_target": 7.0,
|
|
113
115
|
"keep_loudness_range_target": False,
|
|
@@ -153,6 +155,7 @@ class FFmpegNormalize:
|
|
|
153
155
|
normalization_type: Literal["ebu", "rms", "peak"] = "ebu",
|
|
154
156
|
target_level: float = -23.0,
|
|
155
157
|
print_stats: bool = False,
|
|
158
|
+
print_summary: bool = False,
|
|
156
159
|
threshold: float = 0.0,
|
|
157
160
|
loudness_range_target: float = 7.0,
|
|
158
161
|
keep_loudness_range_target: bool = False,
|
|
@@ -212,6 +215,7 @@ class FFmpegNormalize:
|
|
|
212
215
|
self.target_level = check_range(target_level, -99, 0, name="target_level")
|
|
213
216
|
|
|
214
217
|
self.print_stats = print_stats
|
|
218
|
+
self.print_summary = print_summary
|
|
215
219
|
|
|
216
220
|
self.threshold = check_range(threshold, 0, 99, name="threshold")
|
|
217
221
|
|
|
@@ -555,3 +559,97 @@ class FFmpegNormalize:
|
|
|
555
559
|
indent=4,
|
|
556
560
|
)
|
|
557
561
|
print()
|
|
562
|
+
|
|
563
|
+
if self.print_summary:
|
|
564
|
+
print(self.format_summary(), file=sys.stderr)
|
|
565
|
+
|
|
566
|
+
def get_summary(self) -> list[SummaryRow]:
|
|
567
|
+
"""
|
|
568
|
+
Return the before/after summary for all audio streams of all files.
|
|
569
|
+
|
|
570
|
+
Each entry contains the input level, output level, output peak and the
|
|
571
|
+
applied gain in dB. The level is the integrated loudness for EBU, the
|
|
572
|
+
RMS level for RMS, and the peak level for peak normalization. The
|
|
573
|
+
output peak is the true peak for EBU and the sample peak otherwise.
|
|
574
|
+
Values that are not available are None.
|
|
575
|
+
|
|
576
|
+
Returns:
|
|
577
|
+
list[SummaryRow]: One summary entry per audio stream
|
|
578
|
+
"""
|
|
579
|
+
return list(
|
|
580
|
+
chain.from_iterable(
|
|
581
|
+
media_file.get_summary() for media_file in self.media_files
|
|
582
|
+
)
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
def format_summary(self) -> str:
|
|
586
|
+
"""
|
|
587
|
+
Return the before/after summary as a human-readable table.
|
|
588
|
+
|
|
589
|
+
Returns:
|
|
590
|
+
str: The formatted table, including a header line with the target
|
|
591
|
+
"""
|
|
592
|
+
if self.normalization_type == "ebu":
|
|
593
|
+
header = (
|
|
594
|
+
f"EBU R128 normalization, target: {self.target_level:.1f} LUFS, "
|
|
595
|
+
f"true peak: {self.true_peak:.1f} dBTP"
|
|
596
|
+
)
|
|
597
|
+
if self.dynamic:
|
|
598
|
+
header += ", dynamic mode"
|
|
599
|
+
columns = ["Input (LUFS)", "Output (LUFS)", "True peak (dBTP)", "Gain (dB)"]
|
|
600
|
+
elif self.normalization_type == "rms":
|
|
601
|
+
header = f"RMS normalization, target: {self.target_level:.1f} dBFS"
|
|
602
|
+
columns = [
|
|
603
|
+
"Input RMS (dBFS)",
|
|
604
|
+
"Output RMS (dBFS)",
|
|
605
|
+
"Peak (dBFS)",
|
|
606
|
+
"Gain (dB)",
|
|
607
|
+
]
|
|
608
|
+
else:
|
|
609
|
+
header = f"Peak normalization, target: {self.target_level:.1f} dBFS"
|
|
610
|
+
columns = ["Input peak (dBFS)", "Output peak (dBFS)", "Gain (dB)"]
|
|
611
|
+
|
|
612
|
+
if self.batch:
|
|
613
|
+
header += ", batch mode (relative loudness preserved)"
|
|
614
|
+
if self.dry_run:
|
|
615
|
+
header += ", dry run"
|
|
616
|
+
|
|
617
|
+
rows = self.get_summary()
|
|
618
|
+
if not rows:
|
|
619
|
+
return f"Summary ({header}): no files processed"
|
|
620
|
+
|
|
621
|
+
def fmt(value: float | None, signed: bool = False) -> str:
|
|
622
|
+
if value is None:
|
|
623
|
+
return "-"
|
|
624
|
+
return f"{value:+.1f}" if signed else f"{value:.1f}"
|
|
625
|
+
|
|
626
|
+
table: list[list[str]] = []
|
|
627
|
+
for row in rows:
|
|
628
|
+
values = [fmt(row["input_level"]), fmt(row["output_level"])]
|
|
629
|
+
if self.normalization_type != "peak":
|
|
630
|
+
values.append(fmt(row["output_peak"]))
|
|
631
|
+
values.append(fmt(row["gain"], signed=True))
|
|
632
|
+
table.append(
|
|
633
|
+
[row["input_file"], str(row["stream_id"]), *values, row["status"]]
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
headings = ["File", "Stream", *columns, "Status"]
|
|
637
|
+
widths = [
|
|
638
|
+
max(len(headings[i]), *(len(line[i]) for line in table))
|
|
639
|
+
for i in range(len(headings))
|
|
640
|
+
]
|
|
641
|
+
|
|
642
|
+
def fmt_line(cells: list[str]) -> str:
|
|
643
|
+
# Left-align the file name and status, right-align everything else
|
|
644
|
+
parts = [
|
|
645
|
+
cell.ljust(widths[i])
|
|
646
|
+
if i in (0, len(cells) - 1)
|
|
647
|
+
else cell.rjust(widths[i])
|
|
648
|
+
for i, cell in enumerate(cells)
|
|
649
|
+
]
|
|
650
|
+
return " ".join(parts).rstrip()
|
|
651
|
+
|
|
652
|
+
lines = [f"Summary ({header}):", "", fmt_line(headings)]
|
|
653
|
+
lines.append(fmt_line(["-" * w for w in widths]))
|
|
654
|
+
lines.extend(fmt_line(line) for line in table)
|
|
655
|
+
return "\n".join(lines)
|
|
@@ -27,6 +27,7 @@ from ._streams import (
|
|
|
27
27
|
AudioStream,
|
|
28
28
|
LoudnessStatisticsWithMetadata,
|
|
29
29
|
SubtitleStream,
|
|
30
|
+
SummaryRow,
|
|
30
31
|
VideoStream,
|
|
31
32
|
)
|
|
32
33
|
|
|
@@ -811,6 +812,7 @@ class MediaFile:
|
|
|
811
812
|
f"Stream {audio_stream.stream_id} had measured input loudness lower than target, skipping normalization."
|
|
812
813
|
)
|
|
813
814
|
normalization_filter = "acopy"
|
|
815
|
+
audio_stream.applied_gain = 0.0
|
|
814
816
|
else:
|
|
815
817
|
if self.ffmpeg_normalize.normalization_type == "ebu":
|
|
816
818
|
normalization_filter = audio_stream.get_second_pass_opts_ebu(
|
|
@@ -1223,3 +1225,23 @@ class MediaFile:
|
|
|
1223
1225
|
return (
|
|
1224
1226
|
audio_stream.get_stats() for audio_stream in self.streams["audio"].values()
|
|
1225
1227
|
)
|
|
1228
|
+
|
|
1229
|
+
def get_summary(self) -> list[SummaryRow]:
|
|
1230
|
+
"""
|
|
1231
|
+
Return the before/after summary for each analyzed audio stream.
|
|
1232
|
+
|
|
1233
|
+
Streams without any measurement (e.g. streams not selected for
|
|
1234
|
+
normalization) are left out, unless the file failed to process.
|
|
1235
|
+
|
|
1236
|
+
Returns:
|
|
1237
|
+
list[SummaryRow]: One summary entry per audio stream
|
|
1238
|
+
"""
|
|
1239
|
+
rows = [
|
|
1240
|
+
audio_stream.get_summary()
|
|
1241
|
+
for audio_stream in self.streams["audio"].values()
|
|
1242
|
+
]
|
|
1243
|
+
return [
|
|
1244
|
+
row
|
|
1245
|
+
for row in rows
|
|
1246
|
+
if row["status"] == "error" or row["input_level"] is not None
|
|
1247
|
+
]
|
|
@@ -59,6 +59,17 @@ class LoudnessStatistics(TypedDict):
|
|
|
59
59
|
max: float | None
|
|
60
60
|
|
|
61
61
|
|
|
62
|
+
class SummaryRow(TypedDict):
|
|
63
|
+
input_file: str
|
|
64
|
+
output_file: str
|
|
65
|
+
stream_id: int
|
|
66
|
+
status: str
|
|
67
|
+
input_level: float | None
|
|
68
|
+
output_level: float | None
|
|
69
|
+
output_peak: float | None
|
|
70
|
+
gain: float | None
|
|
71
|
+
|
|
72
|
+
|
|
62
73
|
class _OptionalStatisticsMetadata(TypedDict, total=False):
|
|
63
74
|
error: str
|
|
64
75
|
|
|
@@ -150,6 +161,11 @@ class AudioStream(MediaStream):
|
|
|
150
161
|
"max": None,
|
|
151
162
|
}
|
|
152
163
|
|
|
164
|
+
# Gain in dB applied by the second pass volume filter (peak/RMS), or 0
|
|
165
|
+
# when normalization is skipped for this stream (e.g. with lower_only).
|
|
166
|
+
# Stays None for EBU, where the gain is derived from the second pass stats.
|
|
167
|
+
self.applied_gain: float | None = None
|
|
168
|
+
|
|
153
169
|
self.sample_rate = sample_rate
|
|
154
170
|
self.bit_depth = bit_depth
|
|
155
171
|
|
|
@@ -208,6 +224,78 @@ class AudioStream(MediaStream):
|
|
|
208
224
|
stats["error"] = self.media_file.error
|
|
209
225
|
return stats
|
|
210
226
|
|
|
227
|
+
def get_summary(self) -> SummaryRow:
|
|
228
|
+
"""
|
|
229
|
+
Return the before/after levels and the applied gain for the stream.
|
|
230
|
+
|
|
231
|
+
For EBU, the input level and true peak come from the first pass (or the
|
|
232
|
+
second pass in dynamic mode), and the output level, output true peak and
|
|
233
|
+
gain come from the second pass. For RMS and peak, the input level is the
|
|
234
|
+
measured RMS or peak level, and the output values are computed from the
|
|
235
|
+
applied gain. Values that are not available are None.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
dict: A dictionary with the summary values.
|
|
239
|
+
"""
|
|
240
|
+
normalization_type = self.ffmpeg_normalize.normalization_type
|
|
241
|
+
status = self.media_file.status
|
|
242
|
+
|
|
243
|
+
input_level: float | None = None
|
|
244
|
+
input_peak: float | None = None
|
|
245
|
+
output_level: float | None = None
|
|
246
|
+
output_peak: float | None = None
|
|
247
|
+
gain: float | None = None
|
|
248
|
+
|
|
249
|
+
if normalization_type == "ebu":
|
|
250
|
+
pass1 = self.loudness_statistics["ebu_pass1"]
|
|
251
|
+
pass2 = self.loudness_statistics["ebu_pass2"]
|
|
252
|
+
input_stats = pass1 if pass1 is not None else pass2
|
|
253
|
+
if input_stats is not None:
|
|
254
|
+
input_level = float(input_stats["input_i"])
|
|
255
|
+
input_peak = float(input_stats["input_tp"])
|
|
256
|
+
if pass2 is not None:
|
|
257
|
+
output_level = float(pass2["output_i"])
|
|
258
|
+
output_peak = float(pass2["output_tp"])
|
|
259
|
+
# Input and output of the same pass, as the first pass input
|
|
260
|
+
# measurement can differ slightly from the second pass one
|
|
261
|
+
gain = output_level - float(pass2["input_i"])
|
|
262
|
+
else:
|
|
263
|
+
measured = (
|
|
264
|
+
self.loudness_statistics["mean"]
|
|
265
|
+
if normalization_type == "rms"
|
|
266
|
+
else self.loudness_statistics["max"]
|
|
267
|
+
)
|
|
268
|
+
if measured is not None:
|
|
269
|
+
input_level = float(measured)
|
|
270
|
+
if self.loudness_statistics["max"] is not None:
|
|
271
|
+
input_peak = float(self.loudness_statistics["max"])
|
|
272
|
+
|
|
273
|
+
applied_gain = 0.0 if status == "skipped" else self.applied_gain
|
|
274
|
+
if (
|
|
275
|
+
status != "error"
|
|
276
|
+
and output_level is None
|
|
277
|
+
and applied_gain is not None
|
|
278
|
+
and input_level is not None
|
|
279
|
+
):
|
|
280
|
+
gain = applied_gain
|
|
281
|
+
output_level = input_level + applied_gain
|
|
282
|
+
if input_peak is not None:
|
|
283
|
+
output_peak = input_peak + applied_gain
|
|
284
|
+
|
|
285
|
+
if status == "error":
|
|
286
|
+
output_level = output_peak = gain = None
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
"input_file": self.media_file.input_file,
|
|
290
|
+
"output_file": self.media_file.output_file,
|
|
291
|
+
"stream_id": self.stream_id,
|
|
292
|
+
"status": status,
|
|
293
|
+
"input_level": input_level,
|
|
294
|
+
"output_level": output_level,
|
|
295
|
+
"output_peak": output_peak,
|
|
296
|
+
"gain": gain,
|
|
297
|
+
}
|
|
298
|
+
|
|
211
299
|
def set_second_pass_stats(self, stats: EbuLoudnessStatistics) -> None:
|
|
212
300
|
"""
|
|
213
301
|
Set the EBU loudness statistics for the second pass.
|
|
@@ -815,6 +903,8 @@ class AudioStream(MediaStream):
|
|
|
815
903
|
f"Adjusting stream {self.stream_id} by {adjustment} dB to reach {target_level}"
|
|
816
904
|
)
|
|
817
905
|
|
|
906
|
+
self.applied_gain = float(adjustment)
|
|
907
|
+
|
|
818
908
|
clip_amount = self.loudness_statistics["max"] + adjustment
|
|
819
909
|
if clip_amount > 0:
|
|
820
910
|
_logger.warning(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/data/presets/music.json
RENAMED
|
File without changes
|
{ffmpeg_normalize-1.42.0 → ffmpeg_normalize-1.43.0}/src/ffmpeg_normalize/data/presets/podcast.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|