From 5fdeda2ede202eac8ec70f735dafbc524ad82caf Mon Sep 17 00:00:00 2001 From: DiheChen Date: Thu, 5 Nov 2026 12:13:19 +0800 Subject: [PATCH] fix: measure FLAC files that have data after the audio --- internal/lib/wav/decode.go | 6 ++++++ internal/lib/wav/decode_test.go | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/internal/lib/wav/decode.go b/internal/lib/wav/decode.go index 9aee283..601e91f 100644 --- a/internal/lib/wav/decode.go +++ b/internal/lib/wav/decode.go @@ -318,8 +318,13 @@ func newFLACDecoder(r io.Reader) (Decoder, error) { info := stream.Info divisor := float64(int64(1) << (info.BitsPerSample - 1)) d := &streamDecoder{rate: int(info.SampleRate), ch: int(info.NChannels)} + var decoded uint64 d.fill = func() error { for { + // QQ 音乐的 FLAC 在音频之后还有数据:继续读会被当成音频帧报错,整首的分析结果都会作废。NSamples 为 0 表示文件没有声明总数。 + if info.NSamples > 0 && decoded >= info.NSamples { + return io.EOF + } frame, err := stream.ParseNext() if err != nil { return err // 含 io.EOF @@ -328,6 +333,7 @@ func newFLACDecoder(r io.Reader) (Decoder, error) { continue } n := frame.Subframes[0].NSamples + decoded += uint64(n) ch := len(frame.Subframes) out := d.q.buf[d.q.grow(n*ch):] for c, sub := range frame.Subframes { diff --git a/internal/lib/wav/decode_test.go b/internal/lib/wav/decode_test.go index 25bcf98..86bddcf 100644 --- a/internal/lib/wav/decode_test.go +++ b/internal/lib/wav/decode_test.go @@ -271,6 +271,42 @@ func TestDecodeRejectsUndecodableMP3(t *testing.T) { } } +func TestDecodeFLACStopsAtDeclaredSamples(t *testing.T) { + file, err := os.ReadFile("testdata/sine.flac") + if err != nil { + t.Fatal(err) + } + want, err := Decode(bytes.NewReader(file)) + if err != nil { + t.Fatal(err) + } + + withTrailer := append(slices.Clone(file), 0x00, 0x01, 0x02, 0x03) + got, err := Decode(bytes.NewReader(withTrailer)) + if err != nil { + t.Fatalf("音频之后有多余数据:%v", err) + } + if got.Frames() != want.Frames() { + t.Errorf("采样帧 = %d,期望 %d", got.Frames(), want.Frames()) + } + + // STREAMINFO 的总采样数占第 21 字节的低 4 位和之后的 4 个字节,全 0 表示未知。 + undeclared := slices.Clone(file) + undeclared[21] &= 0xF0 + clear(undeclared[22:26]) + got, err = Decode(bytes.NewReader(undeclared)) + if err != nil { + t.Fatal(err) + } + if got.Frames() != want.Frames() { + t.Errorf("未声明总采样数时采样帧 = %d,期望读到文件结束的 %d", got.Frames(), want.Frames()) + } + + if _, err := Decode(bytes.NewReader(file[:len(file)-200])); err == nil { + t.Error("音频比声明的少时应该报错") + } +} + func TestDamageReportsSkippedMP3Data(t *testing.T) { decode := func(t *testing.T, file []byte) Decoder { t.Helper()