Expand the metadata of flac, now you can read the STREAMINFO block

This commit is contained in:
Misakas 2024-05-05 17:45:03 +08:00
parent 3d75831295
commit 779ee174a8
2 changed files with 101 additions and 7 deletions

43
flac.go
View File

@ -14,7 +14,7 @@ type blockType byte
// FLAC block types.
const (
// Stream Info Block 0
StreamInfoBlock blockType = 0
// Padding Block 1
// Application Block 2
// Seektable Block 3
@ -34,8 +34,8 @@ func ReadFLACTags(r io.ReadSeeker) (Metadata, error) {
return nil, errors.New("expected 'fLaC'")
}
m := &metadataFLAC{
newMetadataVorbis(),
m := &MetadataFLAC{
metadataVorbis: newMetadataVorbis(),
}
for {
@ -51,18 +51,24 @@ func ReadFLACTags(r io.ReadSeeker) (Metadata, error) {
return m, nil
}
type metadataFLAC struct {
type MetadataFLAC struct {
*metadataVorbis
MiniBlockSize uint16
MaxBlockSize uint16
SampleRate uint32
TotalSamples uint64
Duration float64
}
func (m *metadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err error) {
func (m *MetadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err error) {
blockHeader, err := readBytes(r, 1)
if err != nil {
return
}
if getBit(blockHeader[0], 7) {
blockHeader[0] ^= (1 << 7)
blockHeader[0] ^= 1 << 7
last = true
}
@ -72,6 +78,8 @@ func (m *metadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err er
}
switch blockType(blockHeader[0]) {
case StreamInfoBlock:
err = m.readStreamInfo(r, blockLen)
case vorbisCommentBlock:
err = m.readVorbisComment(r)
@ -84,6 +92,27 @@ func (m *metadataFLAC) readFLACMetadataBlock(r io.ReadSeeker) (last bool, err er
return
}
func (m *metadataFLAC) FileType() FileType {
func (m *MetadataFLAC) readStreamInfo(r io.ReadSeeker, len int) error {
data := make([]byte, len)
if _, err := r.Read(data); err != nil {
return err
}
m.MiniBlockSize = uint16(data[0])<<8 | uint16(data[1])
m.MaxBlockSize = uint16(data[2])<<8 | uint16(data[3])
m.SampleRate = (uint32(data[10])<<16 | uint32(data[11])<<8 | uint32(data[12])) >> 4
m.TotalSamples = uint64(data[13])<<32 | uint64(data[14])<<24 | uint64(data[15])<<16 | uint64(data[16])<<8 | uint64(data[17])
m.TotalSamples ^= m.TotalSamples >> 36 << 36
m.Duration = float64(m.TotalSamples) / float64(m.SampleRate)
return nil
}
func (m *MetadataFLAC) FileType() FileType {
return FLAC
}

65
flac_test.go Normal file
View File

@ -0,0 +1,65 @@
package tag
import (
"fmt"
"os"
"testing"
)
type expect struct {
file string
sampleRate uint32
totalSamples uint64
duration float64
}
func TestReadFLACTags(t *testing.T) {
testFiles := []expect{
{"./testdata/without_tags/sample.flac", 11025, 37478, 3.399365},
{"./testdata/with_tags/sample.flac", 11025, 37478, 3.399365},
}
for _, testFile := range testFiles {
file, err := os.Open(testFile.file)
if err != nil {
panic(err)
}
defer file.Close()
metadata, err := ReadFLACTags(file)
t.Run("ReadFLACTags", func(t *testing.T) {
if err != nil {
t.Errorf("ReadFLACTags(%s) returned error: %v", testFile.file, err)
}
if metadata == nil {
t.Errorf("ReadFLACTags(%s) returned nil metadata", testFile.file)
}
})
flacMetadata, ok := metadata.(*MetadataFLAC)
t.Run("MetadataFLAC", func(t *testing.T) {
if !ok {
t.Errorf("ReadFLACTags(%s) returned wrong metadata type", testFile.file)
}
})
t.Run("SampleRate", func(t *testing.T) {
if flacMetadata.SampleRate != testFile.sampleRate {
t.Errorf("ReadFLACTags(%s) returned wrong SampleRate: %d", testFile.file, flacMetadata.SampleRate)
}
})
t.Run("TotalSamples", func(t *testing.T) {
if flacMetadata.TotalSamples != testFile.totalSamples {
t.Errorf("ReadFLACTags(%s) returned wrong TotalSamples: %d", testFile.file, flacMetadata.TotalSamples)
}
})
t.Run("Duration", func(t *testing.T) {
if fmt.Sprintf("%.4f", flacMetadata.Duration) != fmt.Sprintf("%.4f", testFile.duration) {
t.Errorf("ReadFLACTags(%s) returned wrong Duration: %f", testFile.file, flacMetadata.Duration)
}
})
}
}