navidrome/core/ffmpeg/flac_streaminfo.go
Deluan 8dee15501f refactor(transcoding): repair piped headers behind one patcher
The FLAC and mp3 repairs had grown into two copies of the same wrapper: the same
lazy peek on the first Read, the same MultiReader hand-off, the same tolerance of
a short read, and the same comment twice. They now share one headerPatcher, with
a prefix function per container.

Transcode no longer selects the patcher by opts.Format. That string is the target
format of a transcoding profile, which users can name anything, so a row called
'mp3 320' running the default mp3 command got no repair at all, while a row whose
command emits FLAC got one only because the FLAC arm was the default. The shared
peek dispatches on the magic bytes instead, which both patchers already had to
check, and leaves anything it does not recognize untouched.

Also drops b2i in favour of gg.If, and lowers the ID3 bound to 64KB: ffmpeg
cannot write an attached picture to a non-seekable output, so the tag ffmpeg
pipes out stays small.
2026-09-24 17:16:04 -04:00

41 lines
1.2 KiB
Go

package ffmpeg
import (
"encoding/binary"
"math"
)
const (
flacPrefixLen = 26 // through the last total_samples byte
flacMaxTotalSamples = 1<<36 - 1
)
// flacPrefix fills in the STREAMINFO total_samples that ffmpeg leaves at 0 when
// writing to a pipe, since a decoder cannot seek a cached FLAC without it.
func (h *headerPatcher) flacPrefix(buf []byte) ([]byte, error) {
buf, err := h.fill(buf, flacPrefixLen)
if err != nil || len(buf) < flacPrefixLen {
return buf, err
}
setFLACTotalSamples(buf, h.duration)
return buf, nil
}
// setFLACTotalSamples takes the rate from the header rather than the transcode
// options, so a resampled (-ar) output still gets the right count.
func setFLACTotalSamples(prefix []byte, duration float32) {
if prefix[4]&0x7F != 0 { // the first metadata block must be STREAMINFO
return
}
// 20-bit rate | 3-bit channels | 5-bit depth | 36-bit total_samples
info := binary.BigEndian.Uint64(prefix[18:])
rate := info >> 44
if rate == 0 || info&flacMaxTotalSamples != 0 {
return
}
total := math.Round(float64(duration) * float64(rate))
if total > flacMaxTotalSamples {
return
}
binary.BigEndian.PutUint64(prefix[18:], info|uint64(total))
}