commit d5dde756fc3200d476325eda5c69f54e6ff9b4d4
parent bf19fbe42f8f291e04a1ded34c3261a5c18007c3
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date: Fri, 18 Sep 2026 13:16:18 -0400
mf: pin the decoder output to 16 bits per sample
Asking the source reader only for PCM lets it hand back whatever width
the source uses, so a 24-bit WAV decoded to 24-bit. That breaks the
s16le output the package documents and Format.BytesPerSample promises:
playback rejected it outright, and anything treating the bytes as int16
would have read garbage.
Diffstat:
1 file changed, 21 insertions(+), 0 deletions(-)
diff --git a/internal/mf/mf.go b/internal/mf/mf.go
@@ -234,6 +234,13 @@ func configureAudioStream(pReader *IMFSourceReader) error {
return fmt.Errorf("setting sub type: %w", err)
}
+ // Pin the sample size. Asking only for PCM lets the reader hand back
+ // whatever width the source happens to use, so a 24-bit file decodes
+ // to 24-bit and breaks the s16le output this package promises.
+ if err := pPartialType.SetUINT32(&MF_MT_AUDIO_BITS_PER_SAMPLE, 16); err != nil {
+ return fmt.Errorf("setting bits per sample: %w", err)
+ }
+
// Select the first audio stream, and deselect all other streams.
if err := pReader.SetStreamSelection(MF_SOURCE_READER_ALL_STREAMS, false); err != nil {
return fmt.Errorf("deselecting audio streams: %w", err)
@@ -776,6 +783,20 @@ func (v *IMFMediaType) SetGUID(guid *GUID, value *GUID) error {
return nil
}
+// SetUINT32 stores an unsigned 32-bit attribute on the media type.
+func (v *IMFMediaType) SetUINT32(guid *GUID, value uint32) error {
+ r, _, _ := syscall.SyscallN(
+ v.VTable.SetUINT32,
+ uintptr(unsafe.Pointer(v)),
+ uintptr(unsafe.Pointer(guid)),
+ uintptr(value),
+ )
+ if r != S_OK {
+ return MFErr{Code: r}
+ }
+ return nil
+}
+
func (v *IMFMediaType) GetUINT32(guid *GUID, punValue *uint32) error {
r, _, _ := syscall.SyscallN(
v.VTable.GetUINT32,