2021-10-28 02:44:09 +03:00
|
|
|
package flac
|
|
|
|
|
|
|
|
// TODO: 24 bit picture length truncate warning
|
|
|
|
// TODO: Cuesheet
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/wader/fq/format"
|
|
|
|
"github.com/wader/fq/format/registry"
|
|
|
|
"github.com/wader/fq/pkg/decode"
|
|
|
|
)
|
|
|
|
|
|
|
|
var flacStreaminfoFormat []*decode.Format
|
|
|
|
var flacPicture []*decode.Format
|
|
|
|
var vorbisCommentFormat []*decode.Format
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
registry.MustRegister(&decode.Format{
|
|
|
|
Name: format.FLAC_METADATABLOCK,
|
|
|
|
Description: "FLAC metadatablock",
|
|
|
|
DecodeFn: metadatablockDecode,
|
|
|
|
Dependencies: []decode.Dependency{
|
|
|
|
{Names: []string{format.FLAC_STREAMINFO}, Formats: &flacStreaminfoFormat},
|
|
|
|
{Names: []string{format.FLAC_PICTURE}, Formats: &flacPicture},
|
|
|
|
{Names: []string{format.VORBIS_COMMENT}, Formats: &vorbisCommentFormat},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
MetadataBlockStreaminfo = 0
|
|
|
|
MetadataBlockPadding = 1
|
|
|
|
MetadataBlockApplication = 2
|
|
|
|
MetadataBlockSeektable = 3
|
|
|
|
MetadataBlockVorbisComment = 4
|
|
|
|
MetadataBlockCuesheet = 5
|
|
|
|
MetadataBlockPicture = 6
|
|
|
|
)
|
|
|
|
|
2021-11-05 17:04:26 +03:00
|
|
|
var metadataBlockNames = decode.UToStr{
|
2021-10-28 02:44:09 +03:00
|
|
|
MetadataBlockStreaminfo: "Streaminfo",
|
|
|
|
MetadataBlockPadding: "Padding",
|
|
|
|
MetadataBlockApplication: "Application",
|
|
|
|
MetadataBlockSeektable: "Seektable",
|
|
|
|
MetadataBlockVorbisComment: "Vorbis comment",
|
|
|
|
MetadataBlockCuesheet: "Cuesheet",
|
|
|
|
MetadataBlockPicture: "Picture",
|
|
|
|
}
|
|
|
|
|
|
|
|
func metadatablockDecode(d *decode.D, in interface{}) interface{} {
|
|
|
|
var hasStreamInfo bool
|
|
|
|
var streamInfo format.FlacStreamInfo
|
|
|
|
|
|
|
|
isLastBlock := d.FieldBool("last_block")
|
2021-11-05 17:04:26 +03:00
|
|
|
typ := d.FieldU7("type", d.MapUToStr(metadataBlockNames))
|
2021-10-28 02:44:09 +03:00
|
|
|
length := d.FieldU24("length")
|
|
|
|
|
|
|
|
switch typ {
|
|
|
|
case MetadataBlockStreaminfo:
|
|
|
|
flacStreaminfoOut, ok := d.Format(flacStreaminfoFormat, nil).(format.FlacStreaminfoOut)
|
|
|
|
if !ok {
|
|
|
|
d.Invalid(fmt.Sprintf("expected FlacStreaminfoOut, got %#+v", flacStreaminfoOut))
|
|
|
|
}
|
|
|
|
hasStreamInfo = true
|
|
|
|
streamInfo = flacStreaminfoOut.StreamInfo
|
|
|
|
case MetadataBlockVorbisComment:
|
|
|
|
d.FieldFormatLen("comment", int64(length*8), vorbisCommentFormat, nil)
|
|
|
|
case MetadataBlockPicture:
|
|
|
|
d.FieldFormatLen("picture", int64(length*8), flacPicture, nil)
|
|
|
|
case MetadataBlockSeektable:
|
|
|
|
seektableCount := length / 18
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldArray("seekpoints", func(d *decode.D) {
|
2021-10-28 02:44:09 +03:00
|
|
|
for i := uint64(0); i < seektableCount; i++ {
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldStruct("seekpoint", func(d *decode.D) {
|
|
|
|
d.FieldU64("sample_number", d.MapUToScalar(decode.UToScalar{
|
|
|
|
0xffff_ffff_ffff_ffff: {Description: "Placeholder"},
|
|
|
|
}))
|
2021-10-28 02:44:09 +03:00
|
|
|
d.FieldU64("offset")
|
|
|
|
d.FieldU16("number_of_samples")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
case MetadataBlockApplication:
|
|
|
|
d.FieldUTF8("id", 4)
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldRawLen("data", int64((length-4)*8))
|
2021-10-28 02:44:09 +03:00
|
|
|
default:
|
2021-11-05 17:04:26 +03:00
|
|
|
d.FieldRawLen("data", int64(length*8))
|
2021-10-28 02:44:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return format.FlacMetadatablockOut{
|
|
|
|
IsLastBlock: isLastBlock,
|
|
|
|
HasStreamInfo: hasStreamInfo,
|
|
|
|
StreamInfo: streamInfo,
|
|
|
|
}
|
|
|
|
}
|