diff --git a/MkvOpusEnc.py b/MkvOpusEnc.py index 8b72afe..587c643 100644 --- a/MkvOpusEnc.py +++ b/MkvOpusEnc.py @@ -83,17 +83,33 @@ def convert_audio_track(stream_index, channels, temp_dir, source_file, should_do # First pass: Analyze the audio to get loudnorm stats print(" - Pass 1: Analyzing...") result = subprocess.run( - ["ffmpeg", "-v", "info", "-i", str(temp_extracted), "-af", "loudnorm=I=-14:LRA=7:tp=-1:print_format=json", "-f", "null", "-"], + ["ffmpeg", "-v", "info", "-i", str(temp_extracted), "-af", "loudnorm=I=-18:LRA=7:tp=-1:print_format=json", "-f", "null", "-"], capture_output=True, text=True, check=True) - stats_lines = result.stderr.strip().split('\n') - stats_json_str = "".join(stats_lines[-12:]) # The JSON block is the last 12 lines - stats = json.loads(stats_json_str) + + # Find the start and end of the JSON block to avoid parsing extra data. + stderr_output = result.stderr + json_start_index = stderr_output.find('{') + if json_start_index == -1: + raise ValueError("Could not find start of JSON block in ffmpeg output for loudnorm analysis.") + + brace_level = 0 + json_end_index = -1 + for i, char in enumerate(stderr_output[json_start_index:]): + if char == '{': + brace_level += 1 + elif char == '}': + brace_level -= 1 + if brace_level == 0: + json_end_index = json_start_index + i + 1 + break + + stats = json.loads(stderr_output[json_start_index:json_end_index]) # Second pass: Apply the normalization using the stats from the first pass print(" - Pass 2: Applying normalization...") run_cmd([ "ffmpeg", "-v", "quiet", "-stats", "-y", "-i", str(temp_extracted), "-af", - f"loudnorm=I=-14:LRA=7:tp=-1:measured_i={stats['input_i']}:measured_lra={stats['input_lra']}:measured_tp={stats['input_tp']}:measured_thresh={stats['input_thresh']}:offset={stats['target_offset']}", + f"loudnorm=I=-18:LRA=7:tp=-1:measured_i={stats['input_i']}:measured_lra={stats['input_lra']}:measured_tp={stats['input_tp']}:measured_thresh={stats['input_thresh']}:offset={stats['target_offset']}", "-c:a", "flac", str(temp_normalized) ]) diff --git a/av1_opus_encoder.py b/av1_opus_encoder.py index abaf13e..102d5f0 100644 --- a/av1_opus_encoder.py +++ b/av1_opus_encoder.py @@ -72,21 +72,35 @@ def convert_audio_track(index, ch, lang, audio_temp_dir, source_file, should_dow # The stats are printed to stderr, so we must use subprocess.run directly to capture it. print(" - Pass 1: Analyzing...") result = subprocess.run( - ["ffmpeg", "-v", "info", "-i", str(temp_extracted), "-af", "loudnorm=I=-14:LRA=7:tp=-1:print_format=json", "-f", "null", "-"], + ["ffmpeg", "-v", "info", "-i", str(temp_extracted), "-af", "loudnorm=I=-18:LRA=7:tp=-1:print_format=json", "-f", "null", "-"], capture_output=True, text=True, check=True) # Find the start of the JSON block in stderr and parse it. # This is more robust than slicing the last N lines. + # We find the start and end of the JSON block to avoid parsing extra data. stderr_output = result.stderr json_start_index = stderr_output.find('{') - stats_json_str = stderr_output[json_start_index:] - stats = json.loads(stats_json_str) + if json_start_index == -1: + raise ValueError("Could not find start of JSON block in ffmpeg output for loudnorm analysis.") + + brace_level = 0 + json_end_index = -1 + for i, char in enumerate(stderr_output[json_start_index:]): + if char == '{': + brace_level += 1 + elif char == '}': + brace_level -= 1 + if brace_level == 0: + json_end_index = json_start_index + i + 1 + break + + stats = json.loads(stderr_output[json_start_index:json_end_index]) # Second pass: Apply the normalization using the stats from the first pass print(" - Pass 2: Applying normalization...") run_cmd([ "ffmpeg", "-v", "quiet", "-stats", "-y", "-i", str(temp_extracted), "-af", - f"loudnorm=I=-14:LRA=7:tp=-1:measured_i={stats['input_i']}:measured_lra={stats['input_lra']}:measured_tp={stats['input_tp']}:measured_thresh={stats['input_thresh']}:offset={stats['target_offset']}", + f"loudnorm=I=-18:LRA=7:tp=-1:measured_i={stats['input_i']}:measured_lra={stats['input_lra']}:measured_tp={stats['input_tp']}:measured_thresh={stats['input_thresh']}:offset={stats['target_offset']}", "-c:a", "flac", str(temp_normalized) ])