ffmpeg-normalize 1.40.0__tar.gz → 1.41.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.40.0 → ffmpeg_normalize-1.41.0}/PKG-INFO +3 -1
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/README.md +2 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/pyproject.toml +1 -1
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/__main__.py +4 -1
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/_cmd_utils.py +129 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/_ffmpeg_normalize.py +39 -18
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/_media_file.py +49 -9
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/LICENSE.md +0 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/__init__.py +0 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/_errors.py +0 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/_logger.py +0 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/_presets.py +0 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/_streams.py +0 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/data/presets/music.json +0 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/data/presets/podcast.json +0 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/data/presets/streaming-video.json +0 -0
- {ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.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.41.0
|
|
4
4
|
Summary: Normalize audio via ffmpeg
|
|
5
5
|
Keywords: ffmpeg,normalize,audio
|
|
6
6
|
Author: Werner Robitza
|
|
@@ -65,6 +65,8 @@ This program normalizes media files to a certain loudness level using the EBU R1
|
|
|
65
65
|
|
|
66
66
|
## 🆕 What's New
|
|
67
67
|
|
|
68
|
+
- Version 1.41.0 automatically picks the correct output audio codec for the output container, so you no longer need to specify `-c:a`/`--audio-codec` unless you want to override the default. PCM is chosen for containers that support it; others will use teh default that ffmpeg picks. See [the usage guide](https://slhck.info/ffmpeg-normalize/usage/file-input-output/#how-the-output-audio-codec-is-chosen) for details.
|
|
69
|
+
|
|
68
70
|
- Version 1.40.0 can optionally **skip files that are already at the target level** via `--threshold` (e.g. `--threshold 0.5`, disabled by default). Such files are copied through unchanged instead of being re-encoded. The `--print-stats` output now includes a per-file `status` (`normalized`, `skipped`, or `error`, plus an `error` message on failure), and the exit code is non-zero if any file failed to process, so a script can tell what happened to each file.
|
|
69
71
|
|
|
70
72
|
Example:
|
|
@@ -34,6 +34,8 @@ This program normalizes media files to a certain loudness level using the EBU R1
|
|
|
34
34
|
|
|
35
35
|
## 🆕 What's New
|
|
36
36
|
|
|
37
|
+
- Version 1.41.0 automatically picks the correct output audio codec for the output container, so you no longer need to specify `-c:a`/`--audio-codec` unless you want to override the default. PCM is chosen for containers that support it; others will use teh default that ffmpeg picks. See [the usage guide](https://slhck.info/ffmpeg-normalize/usage/file-input-output/#how-the-output-audio-codec-is-chosen) for details.
|
|
38
|
+
|
|
37
39
|
- Version 1.40.0 can optionally **skip files that are already at the target level** via `--threshold` (e.g. `--threshold 0.5`, disabled by default). Such files are copied through unchanged instead of being re-encoded. The `--print-stats` output now includes a per-file `status` (`normalized`, `skipped`, or `error`, plus an `error` message on failure), and the exit code is non-zero if any file failed to process, so a script can tell what happened to each file.
|
|
38
40
|
|
|
39
41
|
Example:
|
|
@@ -429,7 +429,10 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
429
429
|
Audio codec to use for output files.
|
|
430
430
|
See `ffmpeg -encoders` for a list.
|
|
431
431
|
|
|
432
|
-
Will use PCM audio with input stream bit depth by default.
|
|
432
|
+
Will use PCM audio with input stream bit depth by default. For output
|
|
433
|
+
containers that cannot store PCM (e.g. MP3, FLAC, Opus), the codec that
|
|
434
|
+
ffmpeg uses by default for that container is chosen automatically, so
|
|
435
|
+
you usually do not need to set this.
|
|
433
436
|
"""
|
|
434
437
|
),
|
|
435
438
|
)
|
|
@@ -44,6 +44,27 @@ DUR_REGEX = re.compile(
|
|
|
44
44
|
r"Duration: (?P<hour>\d{2}):(?P<min>\d{2}):(?P<sec>\d{2})\.(?P<ms>\d{2})"
|
|
45
45
|
)
|
|
46
46
|
|
|
47
|
+
# Containers that cannot store raw PCM audio. For these, the bit-depth-aware PCM
|
|
48
|
+
# default cannot be used, so a real audio codec has to be chosen (either via the
|
|
49
|
+
# -c:a option or by falling back to ffmpeg's own default for the container, see
|
|
50
|
+
# get_muxer_default_audio_encoder()). PCM_INCOMPATIBLE_FORMATS is matched against
|
|
51
|
+
# the -f/--output-format value, PCM_INCOMPATIBLE_EXTS against the output file
|
|
52
|
+
# extension (which additionally lists m4a).
|
|
53
|
+
PCM_INCOMPATIBLE_FORMATS = {"flac", "mp3", "mp4", "ogg", "oga", "opus", "webm"}
|
|
54
|
+
PCM_INCOMPATIBLE_EXTS = {"flac", "mp3", "mp4", "m4a", "ogg", "oga", "opus", "webm"}
|
|
55
|
+
|
|
56
|
+
# Output extensions whose ffmpeg muxer is registered under a different name.
|
|
57
|
+
# ffmpeg's av_guess_format() resolves these internally; for the "-h muxer="
|
|
58
|
+
# query in get_muxer_default_audio_encoder() we need the muxer's own name.
|
|
59
|
+
_MUXER_NAME_FOR_EXT = {
|
|
60
|
+
"m4a": "ipod",
|
|
61
|
+
"m4b": "ipod",
|
|
62
|
+
"m4v": "ipod",
|
|
63
|
+
"aac": "adts",
|
|
64
|
+
"mka": "matroska",
|
|
65
|
+
"mkv": "matroska",
|
|
66
|
+
}
|
|
67
|
+
|
|
47
68
|
|
|
48
69
|
class CommandRunner:
|
|
49
70
|
"""
|
|
@@ -242,6 +263,114 @@ def get_encoder_sample_formats(encoder: str) -> list[str]:
|
|
|
242
263
|
return formats
|
|
243
264
|
|
|
244
265
|
|
|
266
|
+
_codec_encoders_cache: dict[str, list[str]] | None = None
|
|
267
|
+
_muxer_default_encoder_cache: dict[str, str | None] = {}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def _get_codec_encoders() -> dict[str, list[str]]:
|
|
271
|
+
"""
|
|
272
|
+
Map each ffmpeg codec name to its available encoders.
|
|
273
|
+
|
|
274
|
+
Parsed once from ``ffmpeg -codecs`` and cached for the process lifetime. A
|
|
275
|
+
codec with no explicit ``(encoders: ...)`` list uses an encoder of the same
|
|
276
|
+
name, so it maps to an empty list here.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
dict[str, list[str]]: Mapping of codec name to encoder names.
|
|
280
|
+
"""
|
|
281
|
+
global _codec_encoders_cache
|
|
282
|
+
if _codec_encoders_cache is not None:
|
|
283
|
+
return _codec_encoders_cache
|
|
284
|
+
|
|
285
|
+
encoders: dict[str, list[str]] = {}
|
|
286
|
+
try:
|
|
287
|
+
output = (
|
|
288
|
+
CommandRunner()
|
|
289
|
+
.run_command([get_ffmpeg_exe(), "-hide_banner", "-codecs"])
|
|
290
|
+
.get_output()
|
|
291
|
+
)
|
|
292
|
+
for line in output.splitlines():
|
|
293
|
+
# Rows look like: " DEAIL. opus Opus ... (encoders: opus libopus)"
|
|
294
|
+
match = re.match(r"\s*[D.][E.][AVS.][I.][L.][S.]\s+([A-Za-z0-9_]+)", line)
|
|
295
|
+
if not match:
|
|
296
|
+
continue
|
|
297
|
+
enc_match = re.search(r"\(encoders:([^)]*)\)", line)
|
|
298
|
+
encoders[match.group(1)] = enc_match.group(1).split() if enc_match else []
|
|
299
|
+
except (RuntimeError, FFmpegNormalizeError) as e:
|
|
300
|
+
_logger.debug(f"Could not list ffmpeg codecs: {e}")
|
|
301
|
+
|
|
302
|
+
_codec_encoders_cache = encoders
|
|
303
|
+
return encoders
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _resolve_encoder_for_codec(codec_id: str) -> str:
|
|
307
|
+
"""
|
|
308
|
+
Return the encoder ffmpeg uses by default for a codec id.
|
|
309
|
+
|
|
310
|
+
This mirrors ffmpeg's own selection when no encoder is given on the command
|
|
311
|
+
line: the external library wrapper (e.g. ``libopus``) is preferred over an
|
|
312
|
+
experimental native encoder of the same name (``opus``). Codecs without an
|
|
313
|
+
explicit encoder list use an encoder named like the codec itself.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
codec_id: The codec id as reported by ffmpeg (e.g. "opus", "flac").
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
str: The encoder name to pass to ``-c:a``.
|
|
320
|
+
"""
|
|
321
|
+
encoders = _get_codec_encoders().get(codec_id, [])
|
|
322
|
+
lib_variant = f"lib{codec_id}"
|
|
323
|
+
if lib_variant in encoders:
|
|
324
|
+
return lib_variant
|
|
325
|
+
if encoders:
|
|
326
|
+
return encoders[0]
|
|
327
|
+
return codec_id
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def get_muxer_default_audio_encoder(container: str) -> str | None:
|
|
331
|
+
"""
|
|
332
|
+
Return the audio encoder ffmpeg would use by default for a container.
|
|
333
|
+
|
|
334
|
+
This replicates ffmpeg's own per-container choice when no ``-c:a`` is given,
|
|
335
|
+
rather than hardcoding a table, so it tracks whatever the installed ffmpeg
|
|
336
|
+
does (e.g. ``.ogg`` may default to flac on some builds). The container's
|
|
337
|
+
default audio codec is read from ``ffmpeg -h muxer=<name>`` and then mapped
|
|
338
|
+
to a concrete, non-experimental encoder via _resolve_encoder_for_codec().
|
|
339
|
+
|
|
340
|
+
Results are cached per container for the process lifetime, so batch runs only
|
|
341
|
+
query ffmpeg once per container.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
container: Output file extension or ffmpeg format name without a leading
|
|
345
|
+
dot (e.g. "flac", "m4a", "ipod").
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
str | None: The encoder name (e.g. "flac", "libopus"), or None if it
|
|
349
|
+
could not be determined.
|
|
350
|
+
"""
|
|
351
|
+
container = container.lower()
|
|
352
|
+
if container in _muxer_default_encoder_cache:
|
|
353
|
+
return _muxer_default_encoder_cache[container]
|
|
354
|
+
|
|
355
|
+
muxer = _MUXER_NAME_FOR_EXT.get(container, container)
|
|
356
|
+
encoder: str | None = None
|
|
357
|
+
try:
|
|
358
|
+
output = (
|
|
359
|
+
CommandRunner()
|
|
360
|
+
.run_command([get_ffmpeg_exe(), "-hide_banner", "-h", f"muxer={muxer}"])
|
|
361
|
+
.get_output()
|
|
362
|
+
)
|
|
363
|
+
if match := re.search(r"Default audio codec:\s*([A-Za-z0-9_]+)", output):
|
|
364
|
+
encoder = _resolve_encoder_for_codec(match.group(1))
|
|
365
|
+
except (RuntimeError, FFmpegNormalizeError) as e:
|
|
366
|
+
_logger.debug(
|
|
367
|
+
f"Could not determine default audio codec for container '{container}': {e}"
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
_muxer_default_encoder_cache[container] = encoder
|
|
371
|
+
return encoder
|
|
372
|
+
|
|
373
|
+
|
|
245
374
|
def ffmpeg_has_loudnorm() -> bool:
|
|
246
375
|
"""
|
|
247
376
|
Run feature detection on ffmpeg to see if it supports the loudnorm filter.
|
{ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/_ffmpeg_normalize.py
RENAMED
|
@@ -9,7 +9,14 @@ from typing import TYPE_CHECKING, Literal
|
|
|
9
9
|
|
|
10
10
|
from tqdm import tqdm
|
|
11
11
|
|
|
12
|
-
from ._cmd_utils import
|
|
12
|
+
from ._cmd_utils import (
|
|
13
|
+
PCM_INCOMPATIBLE_EXTS,
|
|
14
|
+
PCM_INCOMPATIBLE_FORMATS,
|
|
15
|
+
ffmpeg_has_loudnorm,
|
|
16
|
+
get_ffmpeg_exe,
|
|
17
|
+
get_muxer_default_audio_encoder,
|
|
18
|
+
validate_input_file,
|
|
19
|
+
)
|
|
13
20
|
from ._errors import FFmpegNormalizeError
|
|
14
21
|
from ._media_file import MediaFile
|
|
15
22
|
|
|
@@ -19,8 +26,6 @@ if TYPE_CHECKING:
|
|
|
19
26
|
_logger = logging.getLogger(__name__)
|
|
20
27
|
|
|
21
28
|
NORMALIZATION_TYPES = ("ebu", "rms", "peak")
|
|
22
|
-
PCM_INCOMPATIBLE_FORMATS = {"flac", "mp3", "mp4", "ogg", "oga", "opus", "webm"}
|
|
23
|
-
PCM_INCOMPATIBLE_EXTS = {"flac", "mp3", "mp4", "m4a", "ogg", "oga", "opus", "webm"}
|
|
24
29
|
|
|
25
30
|
|
|
26
31
|
def check_range(number: object, min_r: float, max_r: float, name: str = "") -> float:
|
|
@@ -274,13 +279,21 @@ class FFmpegNormalize:
|
|
|
274
279
|
self.keep_mtime = keep_mtime
|
|
275
280
|
self.keep_bit_depth = keep_bit_depth
|
|
276
281
|
|
|
277
|
-
if
|
|
278
|
-
self.audio_codec is None
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
if self.output_format in PCM_INCOMPATIBLE_FORMATS:
|
|
283
|
+
if self.audio_codec is not None and "pcm" in self.audio_codec:
|
|
284
|
+
raise FFmpegNormalizeError(
|
|
285
|
+
f"Output format {self.output_format} does not support PCM audio. "
|
|
286
|
+
"Please choose a suitable audio codec with the -c:a option."
|
|
287
|
+
)
|
|
288
|
+
if (
|
|
289
|
+
self.audio_codec is None
|
|
290
|
+
and get_muxer_default_audio_encoder(self.output_format) is None
|
|
291
|
+
):
|
|
292
|
+
raise FFmpegNormalizeError(
|
|
293
|
+
f"Output format {self.output_format} does not support PCM audio, "
|
|
294
|
+
"and a default audio codec could not be determined. Please choose "
|
|
295
|
+
"a suitable audio codec with the -c:a option."
|
|
296
|
+
)
|
|
284
297
|
|
|
285
298
|
# replaygain only works for EBU for now
|
|
286
299
|
if self.replaygain and self.normalization_type != "ebu":
|
|
@@ -316,14 +329,22 @@ class FFmpegNormalize:
|
|
|
316
329
|
if not os.path.exists(input_file):
|
|
317
330
|
raise FFmpegNormalizeError(f"file {input_file} does not exist")
|
|
318
331
|
|
|
319
|
-
ext = os.path.splitext(output_file)[1][1:]
|
|
320
|
-
if
|
|
321
|
-
self.audio_codec is None
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
332
|
+
ext = os.path.splitext(output_file)[1][1:].lower()
|
|
333
|
+
if ext in PCM_INCOMPATIBLE_EXTS:
|
|
334
|
+
if self.audio_codec is not None and "pcm" in self.audio_codec:
|
|
335
|
+
raise FFmpegNormalizeError(
|
|
336
|
+
f"Output extension {ext} does not support PCM audio. "
|
|
337
|
+
"Please choose a suitable audio codec with the -c:a option."
|
|
338
|
+
)
|
|
339
|
+
if (
|
|
340
|
+
self.audio_codec is None
|
|
341
|
+
and get_muxer_default_audio_encoder(ext) is None
|
|
342
|
+
):
|
|
343
|
+
raise FFmpegNormalizeError(
|
|
344
|
+
f"Output extension {ext} does not support PCM audio, and a "
|
|
345
|
+
"default audio codec could not be determined. Please choose a "
|
|
346
|
+
"suitable audio codec with the -c:a option."
|
|
347
|
+
)
|
|
327
348
|
|
|
328
349
|
self.media_files.append(MediaFile(self, input_file, output_file))
|
|
329
350
|
self.file_count += 1
|
|
@@ -15,7 +15,13 @@ from mutagen.oggopus import OggOpus
|
|
|
15
15
|
from mutagen.oggvorbis import OggVorbis
|
|
16
16
|
from tqdm import tqdm
|
|
17
17
|
|
|
18
|
-
from ._cmd_utils import
|
|
18
|
+
from ._cmd_utils import (
|
|
19
|
+
DUR_REGEX,
|
|
20
|
+
PCM_INCOMPATIBLE_EXTS,
|
|
21
|
+
PCM_INCOMPATIBLE_FORMATS,
|
|
22
|
+
CommandRunner,
|
|
23
|
+
get_muxer_default_audio_encoder,
|
|
24
|
+
)
|
|
19
25
|
from ._errors import FFmpegNormalizeError
|
|
20
26
|
from ._streams import (
|
|
21
27
|
AudioStream,
|
|
@@ -842,6 +848,40 @@ class MediaFile:
|
|
|
842
848
|
|
|
843
849
|
return filter_complex_cmd, output_labels
|
|
844
850
|
|
|
851
|
+
def _get_audio_codec(self) -> str | None:
|
|
852
|
+
"""
|
|
853
|
+
Return the audio encoder to use for normalized streams, or None to use
|
|
854
|
+
the bit-depth-aware PCM default.
|
|
855
|
+
|
|
856
|
+
An explicit ``--audio-codec`` (``-c:a``) always takes precedence.
|
|
857
|
+
Otherwise, for a container that cannot store PCM (e.g. FLAC, MP3, Opus),
|
|
858
|
+
fall back to the codec ffmpeg itself would default to for that container,
|
|
859
|
+
so audio-only outputs work without requiring ``-c:a``. PCM-friendly
|
|
860
|
+
containers (e.g. WAV, Matroska) keep the lossless PCM default regardless
|
|
861
|
+
of their own muxer default.
|
|
862
|
+
|
|
863
|
+
Returns:
|
|
864
|
+
str | None: The encoder name, or None to use the PCM default.
|
|
865
|
+
"""
|
|
866
|
+
if self.ffmpeg_normalize.audio_codec:
|
|
867
|
+
return self.ffmpeg_normalize.audio_codec
|
|
868
|
+
|
|
869
|
+
output_format = self.ffmpeg_normalize.output_format
|
|
870
|
+
if output_format in PCM_INCOMPATIBLE_FORMATS:
|
|
871
|
+
container = output_format
|
|
872
|
+
elif self.output_ext.lower() in PCM_INCOMPATIBLE_EXTS:
|
|
873
|
+
container = self.output_ext
|
|
874
|
+
else:
|
|
875
|
+
return None
|
|
876
|
+
|
|
877
|
+
encoder = get_muxer_default_audio_encoder(container)
|
|
878
|
+
if encoder is not None:
|
|
879
|
+
_logger.debug(
|
|
880
|
+
f"No audio codec set; using ffmpeg's default '{encoder}' for "
|
|
881
|
+
f"container '{container}'"
|
|
882
|
+
)
|
|
883
|
+
return encoder
|
|
884
|
+
|
|
845
885
|
def _second_pass(self) -> Iterator[float]:
|
|
846
886
|
"""
|
|
847
887
|
Construct the second pass command and run it.
|
|
@@ -934,12 +974,14 @@ class MediaFile:
|
|
|
934
974
|
# Track output audio stream index for codec assignment
|
|
935
975
|
output_audio_idx = 0
|
|
936
976
|
|
|
977
|
+
# Resolve the audio codec once: an explicit --audio-codec wins, otherwise
|
|
978
|
+
# fall back to ffmpeg's own default codec for the output container (None
|
|
979
|
+
# means use the bit-depth-aware PCM default).
|
|
980
|
+
audio_codec = self._get_audio_codec()
|
|
981
|
+
|
|
937
982
|
# set audio codec for normalized streams
|
|
938
983
|
for audio_stream in streams_to_normalize:
|
|
939
|
-
if
|
|
940
|
-
codec = self.ffmpeg_normalize.audio_codec
|
|
941
|
-
else:
|
|
942
|
-
codec = audio_stream.get_pcm_codec()
|
|
984
|
+
codec = audio_codec if audio_codec else audio_stream.get_pcm_codec()
|
|
943
985
|
cmd.extend([f"-c:a:{output_audio_idx}", codec])
|
|
944
986
|
output_audio_idx += 1
|
|
945
987
|
|
|
@@ -950,7 +992,7 @@ class MediaFile:
|
|
|
950
992
|
|
|
951
993
|
# other audio options (if any) - only apply to normalized streams
|
|
952
994
|
if self.ffmpeg_normalize.audio_bitrate:
|
|
953
|
-
if
|
|
995
|
+
if audio_codec == "libvorbis":
|
|
954
996
|
# libvorbis takes just a "-b" option, for some reason
|
|
955
997
|
# https://github.com/slhck/ffmpeg-normalize/issues/277
|
|
956
998
|
cmd.extend(["-b", str(self.ffmpeg_normalize.audio_bitrate)])
|
|
@@ -972,9 +1014,7 @@ class MediaFile:
|
|
|
972
1014
|
# carry the input bit depth through to the output encoder, if requested
|
|
973
1015
|
if self.ffmpeg_normalize.keep_bit_depth:
|
|
974
1016
|
for idx, audio_stream in enumerate(streams_to_normalize):
|
|
975
|
-
sample_fmt = audio_stream.get_output_sample_fmt(
|
|
976
|
-
self.ffmpeg_normalize.audio_codec
|
|
977
|
-
)
|
|
1017
|
+
sample_fmt = audio_stream.get_output_sample_fmt(audio_codec)
|
|
978
1018
|
if sample_fmt is not None:
|
|
979
1019
|
cmd.extend([f"-sample_fmt:a:{idx}", sample_fmt])
|
|
980
1020
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/data/presets/music.json
RENAMED
|
File without changes
|
{ffmpeg_normalize-1.40.0 → ffmpeg_normalize-1.41.0}/src/ffmpeg_normalize/data/presets/podcast.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|