ffmpeg-normalize 1.32.2__py2.py3-none-any.whl → 1.32.4__py2.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.
- ffmpeg_normalize/_ffmpeg_normalize.py +1 -1
- ffmpeg_normalize/_media_file.py +19 -3
- ffmpeg_normalize/_streams.py +22 -0
- ffmpeg_normalize/_version.py +1 -1
- {ffmpeg_normalize-1.32.2.dist-info → ffmpeg_normalize-1.32.4.dist-info}/METADATA +33 -5
- ffmpeg_normalize-1.32.4.dist-info/RECORD +16 -0
- {ffmpeg_normalize-1.32.2.dist-info → ffmpeg_normalize-1.32.4.dist-info}/WHEEL +1 -1
- ffmpeg_normalize-1.32.2.dist-info/RECORD +0 -16
- {ffmpeg_normalize-1.32.2.dist-info → ffmpeg_normalize-1.32.4.dist-info}/entry_points.txt +0 -0
- {ffmpeg_normalize-1.32.2.dist-info → ffmpeg_normalize-1.32.4.dist-info/licenses}/LICENSE +0 -0
- {ffmpeg_normalize-1.32.2.dist-info → ffmpeg_normalize-1.32.4.dist-info}/top_level.txt +0 -0
|
@@ -63,7 +63,7 @@ class FFmpegNormalize:
|
|
|
63
63
|
lower_only (bool, optional): Whether the audio should not increase in loudness. Defaults to False.
|
|
64
64
|
auto_lower_loudness_target (bool, optional): Automatically lower EBU Integrated Loudness Target.
|
|
65
65
|
dual_mono (bool, optional): Dual mono. Defaults to False.
|
|
66
|
-
dynamic (bool, optional):
|
|
66
|
+
dynamic (bool, optional): Use dynamic EBU R128 normalization. This is a one-pass algorithm and skips the initial media scan. Defaults to False.
|
|
67
67
|
audio_codec (str, optional): Audio codec. Defaults to "pcm_s16le".
|
|
68
68
|
audio_bitrate (float, optional): Audio bitrate. Defaults to None.
|
|
69
69
|
sample_rate (int, optional): Sample rate. Defaults to None.
|
ffmpeg_normalize/_media_file.py
CHANGED
|
@@ -207,8 +207,16 @@ class MediaFile:
|
|
|
207
207
|
"""
|
|
208
208
|
_logger.debug(f"Running normalization for {self.input_file}")
|
|
209
209
|
|
|
210
|
-
# run the first pass to get loudness stats
|
|
211
|
-
|
|
210
|
+
# run the first pass to get loudness stats, unless in dynamic EBU mode
|
|
211
|
+
if not (
|
|
212
|
+
self.ffmpeg_normalize.dynamic
|
|
213
|
+
and self.ffmpeg_normalize.normalization_type == "ebu"
|
|
214
|
+
):
|
|
215
|
+
self._first_pass()
|
|
216
|
+
else:
|
|
217
|
+
_logger.debug(
|
|
218
|
+
"Dynamic EBU mode: First pass will not run, as it is not needed."
|
|
219
|
+
)
|
|
212
220
|
|
|
213
221
|
# for second pass, create a temp file
|
|
214
222
|
temp_dir = mkdtemp()
|
|
@@ -596,6 +604,10 @@ class MediaFile:
|
|
|
596
604
|
yield 100
|
|
597
605
|
return
|
|
598
606
|
|
|
607
|
+
# track temp_dir for cleanup
|
|
608
|
+
temp_dir = None
|
|
609
|
+
temp_file = None
|
|
610
|
+
|
|
599
611
|
# special case: if output is a null device, write directly to it
|
|
600
612
|
if self.output_file == os.devnull:
|
|
601
613
|
cmd.append(self.output_file)
|
|
@@ -612,11 +624,15 @@ class MediaFile:
|
|
|
612
624
|
raise e
|
|
613
625
|
else:
|
|
614
626
|
# only move the temp file if it's not a null device and ReplayGain is not enabled!
|
|
615
|
-
if self.output_file != os.devnull and not self.ffmpeg_normalize.replaygain:
|
|
627
|
+
if self.output_file != os.devnull and temp_file and not self.ffmpeg_normalize.replaygain:
|
|
616
628
|
_logger.debug(
|
|
617
629
|
f"Moving temporary file from {temp_file} to {self.output_file}"
|
|
618
630
|
)
|
|
619
631
|
move(temp_file, self.output_file)
|
|
632
|
+
finally:
|
|
633
|
+
# clean up temp directory if it was created
|
|
634
|
+
if temp_dir and os.path.exists(temp_dir):
|
|
635
|
+
rmtree(temp_dir, ignore_errors=True)
|
|
620
636
|
|
|
621
637
|
output = cmd_runner.get_output()
|
|
622
638
|
# in the second pass, we do not normalize stream-by-stream, so we set the stats based on the
|
ffmpeg_normalize/_streams.py
CHANGED
|
@@ -428,6 +428,28 @@ class AudioStream(MediaStream):
|
|
|
428
428
|
Return second pass loudnorm filter options string for ffmpeg
|
|
429
429
|
"""
|
|
430
430
|
|
|
431
|
+
# In dynamic mode, we can do everything in one pass, and we do not have first pass stats
|
|
432
|
+
if self.media_file.ffmpeg_normalize.dynamic:
|
|
433
|
+
if not self.ffmpeg_normalize.sample_rate:
|
|
434
|
+
_logger.warning(
|
|
435
|
+
"In dynamic mode, the sample rate will automatically be set to 192 kHz by the loudnorm filter. "
|
|
436
|
+
"Specify -ar/--sample-rate to override it."
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
opts = {
|
|
440
|
+
"i": self.media_file.ffmpeg_normalize.target_level,
|
|
441
|
+
"lra": self.media_file.ffmpeg_normalize.loudness_range_target,
|
|
442
|
+
"tp": self.media_file.ffmpeg_normalize.true_peak,
|
|
443
|
+
"offset": self.media_file.ffmpeg_normalize.offset,
|
|
444
|
+
"linear": "false",
|
|
445
|
+
"print_format": "json",
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if self.media_file.ffmpeg_normalize.dual_mono:
|
|
449
|
+
opts["dual_mono"] = "true"
|
|
450
|
+
|
|
451
|
+
return "loudnorm=" + dict_to_filter_opts(opts)
|
|
452
|
+
|
|
431
453
|
if not self.loudness_statistics["ebu_pass1"]:
|
|
432
454
|
raise FFmpegNormalizeError(
|
|
433
455
|
"First pass not run, you must call parse_loudnorm_stats first"
|
ffmpeg_normalize/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.32.
|
|
1
|
+
__version__ = "1.32.4"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
2
|
-
Name:
|
|
3
|
-
Version: 1.32.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ffmpeg_normalize
|
|
3
|
+
Version: 1.32.4
|
|
4
4
|
Summary: Normalize audio via ffmpeg
|
|
5
5
|
Home-page: https://github.com/slhck/ffmpeg-normalize
|
|
6
6
|
Author: Werner Robitza
|
|
@@ -24,10 +24,22 @@ Requires-Python: >=3.9
|
|
|
24
24
|
Description-Content-Type: text/markdown
|
|
25
25
|
License-File: LICENSE
|
|
26
26
|
Requires-Dist: tqdm
|
|
27
|
+
Requires-Dist: colorama; platform_system == "Windows"
|
|
27
28
|
Requires-Dist: ffmpeg-progress-yield
|
|
28
29
|
Requires-Dist: colorlog
|
|
29
30
|
Requires-Dist: mutagen
|
|
30
|
-
|
|
31
|
+
Dynamic: author
|
|
32
|
+
Dynamic: author-email
|
|
33
|
+
Dynamic: classifier
|
|
34
|
+
Dynamic: description
|
|
35
|
+
Dynamic: description-content-type
|
|
36
|
+
Dynamic: home-page
|
|
37
|
+
Dynamic: keywords
|
|
38
|
+
Dynamic: license
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
Dynamic: requires-dist
|
|
41
|
+
Dynamic: requires-python
|
|
42
|
+
Dynamic: summary
|
|
31
43
|
|
|
32
44
|
# ffmpeg-normalize
|
|
33
45
|
|
|
@@ -45,7 +57,7 @@ This program normalizes media files to a certain loudness level using the EBU R1
|
|
|
45
57
|
|
|
46
58
|
## ✨ Features
|
|
47
59
|
|
|
48
|
-
- EBU R128 loudness normalization
|
|
60
|
+
- EBU R128 loudness normalization (two-pass by default, with an option for one-pass dynamic normalization)
|
|
49
61
|
- RMS-based normalization
|
|
50
62
|
- Peak normalization
|
|
51
63
|
- Video file support
|
|
@@ -119,6 +131,22 @@ The only reason this project exists in its current form is because [@benjaoming]
|
|
|
119
131
|
# Changelog
|
|
120
132
|
|
|
121
133
|
|
|
134
|
+
## v1.32.4 (2025-06-08)
|
|
135
|
+
|
|
136
|
+
* Update api docs.
|
|
137
|
+
|
|
138
|
+
* Update docs.
|
|
139
|
+
|
|
140
|
+
* Make --dynamic option use one pass only, fixes #263.
|
|
141
|
+
|
|
142
|
+
* Fix type error.
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
## v1.32.3 (2025-05-30)
|
|
146
|
+
|
|
147
|
+
* Fix temp dir cleanup, fixes #284.
|
|
148
|
+
|
|
149
|
+
|
|
122
150
|
## v1.32.2 (2025-05-08)
|
|
123
151
|
|
|
124
152
|
* Docs: reference changelog.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
ffmpeg_normalize/__init__.py,sha256=aAhlk93ZE6SQcWUDzZQcw9vJh0bJcKEUNFGhVc5ZIto,453
|
|
2
|
+
ffmpeg_normalize/__main__.py,sha256=LMj4Xl140ZKe5naY36fAwzz72lK59srzkVlbb0KzkcQ,19955
|
|
3
|
+
ffmpeg_normalize/_cmd_utils.py,sha256=iGzO3iOylDUOnx-FCKd84BMxiIhmIthxU1tg7kvf4Ss,5269
|
|
4
|
+
ffmpeg_normalize/_errors.py,sha256=brTQ4osJ4fTA8wnyMPVVYfGwJ0wqeShRFydTEwi_VEY,48
|
|
5
|
+
ffmpeg_normalize/_ffmpeg_normalize.py,sha256=_ZK2P3kAM0mnxY3iCYH61T6jhMndTdO2Rqh03vJo7rY,11852
|
|
6
|
+
ffmpeg_normalize/_logger.py,sha256=3Ap4Fxg7xGrzz7h4IGuNEf0KKstx0Rq_eLbHPrHzcrI,1841
|
|
7
|
+
ffmpeg_normalize/_media_file.py,sha256=6QYGIlNFpxojYjof_3y1HoU8SgsVnMor2y4hx-22CVY,26323
|
|
8
|
+
ffmpeg_normalize/_streams.py,sha256=tg4D5UMBFpPFxK5x-HG6mwgqkm9Z6H1kH14OlaCXM-A,21590
|
|
9
|
+
ffmpeg_normalize/_version.py,sha256=kVLezpNpKw6uZIvSwisQSFv3H0SHTGxoH32YSRqVSpQ,23
|
|
10
|
+
ffmpeg_normalize/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
ffmpeg_normalize-1.32.4.dist-info/licenses/LICENSE,sha256=mw5RQE6v4UXG_d2gYIQw9rq6jYWQCtzIs3fSm5sBSrs,1076
|
|
12
|
+
ffmpeg_normalize-1.32.4.dist-info/METADATA,sha256=kEvnRedCUL1slT6bbN7m--Hhpgw7yvixyrULe-f2MPQ,33285
|
|
13
|
+
ffmpeg_normalize-1.32.4.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
|
14
|
+
ffmpeg_normalize-1.32.4.dist-info/entry_points.txt,sha256=X0EC5ptb0iGOxrk3Aa65dVQtvUixngLd_2-iAtSixdc,68
|
|
15
|
+
ffmpeg_normalize-1.32.4.dist-info/top_level.txt,sha256=wnUkr17ckPrrU1JsxZQiXbEBUnHKsC64yck-MemEBuI,17
|
|
16
|
+
ffmpeg_normalize-1.32.4.dist-info/RECORD,,
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
ffmpeg_normalize/__init__.py,sha256=aAhlk93ZE6SQcWUDzZQcw9vJh0bJcKEUNFGhVc5ZIto,453
|
|
2
|
-
ffmpeg_normalize/__main__.py,sha256=LMj4Xl140ZKe5naY36fAwzz72lK59srzkVlbb0KzkcQ,19955
|
|
3
|
-
ffmpeg_normalize/_cmd_utils.py,sha256=iGzO3iOylDUOnx-FCKd84BMxiIhmIthxU1tg7kvf4Ss,5269
|
|
4
|
-
ffmpeg_normalize/_errors.py,sha256=brTQ4osJ4fTA8wnyMPVVYfGwJ0wqeShRFydTEwi_VEY,48
|
|
5
|
-
ffmpeg_normalize/_ffmpeg_normalize.py,sha256=79wzFR4ZOgy-Wn0ywi8PNJzsrxiDSMKtJ6_auHxiQvo,11762
|
|
6
|
-
ffmpeg_normalize/_logger.py,sha256=3Ap4Fxg7xGrzz7h4IGuNEf0KKstx0Rq_eLbHPrHzcrI,1841
|
|
7
|
-
ffmpeg_normalize/_media_file.py,sha256=E1PugUYf-SyOAbtPkJ3UHNfrJR3Ed5KaO8OOT9UHh8k,25737
|
|
8
|
-
ffmpeg_normalize/_streams.py,sha256=w-gzAFUbnoLiRABckUgYqdhVgidtEATNd3di-jiP9fU,20599
|
|
9
|
-
ffmpeg_normalize/_version.py,sha256=WdfJcWchCw6txwQmjH_WAwImubvfgUZlGyLcv7_k8f4,23
|
|
10
|
-
ffmpeg_normalize/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
ffmpeg_normalize-1.32.2.dist-info/LICENSE,sha256=mw5RQE6v4UXG_d2gYIQw9rq6jYWQCtzIs3fSm5sBSrs,1076
|
|
12
|
-
ffmpeg_normalize-1.32.2.dist-info/METADATA,sha256=mZweBzs3rrgkjaVbr3H3jzaU4H3bMUO8MN0COu15ZTM,32758
|
|
13
|
-
ffmpeg_normalize-1.32.2.dist-info/WHEEL,sha256=fS9sRbCBHs7VFcwJLnLXN1MZRR0_TVTxvXKzOnaSFs8,110
|
|
14
|
-
ffmpeg_normalize-1.32.2.dist-info/entry_points.txt,sha256=X0EC5ptb0iGOxrk3Aa65dVQtvUixngLd_2-iAtSixdc,68
|
|
15
|
-
ffmpeg_normalize-1.32.2.dist-info/top_level.txt,sha256=wnUkr17ckPrrU1JsxZQiXbEBUnHKsC64yck-MemEBuI,17
|
|
16
|
-
ffmpeg_normalize-1.32.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|