Skip to content

Fix MP3 duration regression when metadata overestimates the decoder length - #119

Open
ctompos wants to merge 1 commit into
LSXPrime:masterfrom
ctompos:fix/mp3-duration-regression
Open

ctompos wants to merge 1 commit into
LSXPrime:masterfrom
ctompos:fix/mp3-duration-regression

Conversation

@ctompos

@ctompos ctompos commented Oct 24, 2026

Copy link
Copy Markdown

Fix MP3 duration regression when metadata overestimates the decoder length

A 192 kb/s MPEG-1 MP3 without a Xing/Info header is read as 112 kb/s, and the 1.4.2 provider chooses that inflated metadata estimate over the decoder's known length. A file that decodes to 10.032 seconds consequently reports 17.198 seconds and accepts seeks past its actual end.

Select the MPEG-version bitrate row for Layer III, preserving the single-row lookups for the other layers. Prefer a positive decoder length and use metadata only when the decoder length is unknown. Convert that fallback into output samples using the decoder's sample rate and channel count, retaining the range checks. The example above now reports 10.032 seconds and rejects a seek to 12 seconds.

Closes #118.

Validation

  • Release build of the core library: zero warnings or errors, targeting .NET 8 on Windows x64 with SDK 10.0.402.
  • A local validation harness outside the PR checks MPEG bitrate tables, decoder-length precedence, fallback output units, unknown/invalid durations, and overflow: 21 checks pass. Four additional freshly encoded 10-second CBR cases (44.1/48 kHz, with/without Info headers) pass against sequential decoding.
  • The local harness fails against the unmodified 1.4.2 package with expected 192000, got 112000 and exits successfully with this patch.
  • The original 130-minute CBR file without an Info header reports 7,800.033 seconds instead of 12,285.041 seconds. Long VBR files with and without Xing headers also retain their decoder-reported duration.
  • Two-hour seeks remain approximately 7 ms using the released 1.4.2 MiniAudio runtime. Native code and the seek-point setting are unchanged.

The minimal reproduction and file-generation command are included in #118. Build the core library from the repository root with:

dotnet build Src/SoundFlow.csproj -c Release

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Welcome to SoundFlow repository! We appreciate you taking the time to contribute.

We're excited to review your pull request and look forward to collaborating with you. Please let us know if you have any questions or need any assistance.

Thank you for your contribution!

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Fix MP3 duration when metadata exceeds decoder length

🐞 Bug fix 🕐 10-20 Minutes

Grey Divider

AI Description

• Correct MPEG-1 Layer III bitrate metadata used to estimate duration without a Xing header.
• Prefer known decoder length, preventing inflated durations and seeks beyond the decoded audio.
• Convert fallback metadata duration to decoder output samples when decoder length is unknown.
Diagram

graph TD
  A["MP3 stream"] --> B["MP3 reader"] --> C["Metadata estimate"] --> E{"Decoder length known?"} --> F["Provider length"] --> G["Seek validation"]
  A --> D["PCM decoder"] --> E
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Scan MP3 frames for duration
  • ➕ Could produce a more accurate fallback for VBR files without Xing headers when decoder length is unknown.
  • ➖ Adds file traversal and initialization cost to address cases outside this regression.
  • ➖ Does not remove the need to prefer a known decoder length.

Recommendation: Keep the focused bitrate correction and decoder-first precedence. A frame scan is worth considering separately only if inaccurate fallback durations remain significant for files whose decoders cannot report length.

Files changed (2) +19 / -39

Bug fix (2) +19 / -39
Mp3Reader.csSelect the MPEG-version bitrate row for Layer III +2/-1

Select the MPEG-version bitrate row for Layer III

• Layer III bitrate lookup now uses the MPEG version's row, correcting MPEG-1 metadata estimates. Other layers retain their single-row lookup.

Src/Metadata/Readers/Format/Mp3Reader.cs

StreamDataProvider.csPrefer decoder length over metadata duration +17/-38

Prefer decoder length over metadata duration

• Length now returns a positive decoder value rather than the larger of two estimates. When decoder length is unknown, it converts valid metadata duration using the decoder's output sample rate and channels, returning zero for invalid or out-of-range estimates.

Src/Providers/StreamDataProvider.cs

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Tip of the day
💡 Did you know, you can choose which labels appear on a finding, and whether they show icons or text

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@greptile-apps

greptile-apps Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The changes reach MP3 duration estimates and stream-backed audio lengths.

The PR appears safe to merge, with a non-blocking request to check in the regression tests.

Findings

  1. P2 Regression checks aren't checked in ▶
Fix with agent prompt
### Issue 1
Src/Providers/StreamDataProvider.cs:135-145
The checks described in the PR live outside the repository, so they cannot catch future changes that restore the wrong duration or seek limit. Please check in tests for the MPEG-version bitrate rows, a positive decoder length smaller than metadata, and an unknown decoder length with different source and output formats. Include invalid durations and the `int.MaxValue` boundary.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Fixes MP3 bitrate lookup and makes StreamDataProvider.Length prefer a positive decoder length.

  • MP3 metadata uses the right bitrate row for each MPEG version.
  • Stream lengths follow decoded audio when its length is known.

Reviews (1) · Last reviewed commit: "fix: preserve decoder length and correct..." · Reviewed by Greptile

Comment on lines 135 to +145
var decoderLength = _decoder.Length;

int metadataLength;
if (FormatInfo != null
&& FormatInfo.Duration > TimeSpan.Zero
&& FormatInfo.SampleRate > 0
&& FormatInfo.ChannelCount > 0)
{
var metadataLengthSamples = FormatInfo.Duration.TotalSeconds
* FormatInfo.SampleRate
* FormatInfo.ChannelCount;

if (metadataLengthSamples is >= 0 and <= int.MaxValue)
metadataLength = (int)metadataLengthSamples;
else
metadataLength = 0;
}
else
{
metadataLength = 0;
}
if (decoderLength > 0)
return decoderLength;

return decoderLength switch
{
// Prefer the larger value when both are available. See the XML doc above for the rationale.
// Special case: if one of them is 0 (unknown), use the other.
> 0 when metadataLength > 0 => Math.Max(decoderLength, metadataLength),
> 0 => decoderLength,
_ => metadataLength
};
if (FormatInfo == null || FormatInfo.Duration <= TimeSpan.Zero
|| _decoder.SampleRate <= 0 || _decoder.Channels <= 0)
return 0;

var metadataLengthSamples = FormatInfo.Duration.TotalSeconds
* _decoder.SampleRate
* _decoder.Channels;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Regression checks aren't checked in

The checks described in the PR live outside the repository, so they cannot catch future changes that restore the wrong duration or seek limit. Please check in tests for the MPEG-version bitrate rows, a positive decoder length smaller than metadata, and an unknown decoder length with different source and output formats. Include invalid durations and the int.MaxValue boundary.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Src/Providers/StreamDataProvider.cs
Line: 135-145

Comment:
**Regression checks aren't checked in**

The checks described in the PR live outside the repository, so they cannot catch future changes that restore the wrong duration or seek limit. Please check in tests for the MPEG-version bitrate rows, a positive decoder length smaller than metadata, and an unknown decoder length with different source and output formats. Include invalid durations and the `int.MaxValue` boundary.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] 1.4.2 overstates duration of CBR MP3s without Xing/Info headers

1 participant