mirror of
https://github.com/wader/fq.git
synced 2024-12-26 15:02:28 +03:00
e9d9f8aef9
Rename s/interface{}/any/g Preparation for using generics in decode API and native jq funcations etc Remove some unused linter ignores as linter has been fixed
125 lines
3.3 KiB
Go
125 lines
3.3 KiB
Go
package opus
|
|
|
|
// https://tools.ietf.org/html/rfc7845
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/wader/fq/format"
|
|
"github.com/wader/fq/format/registry"
|
|
"github.com/wader/fq/pkg/decode"
|
|
)
|
|
|
|
var vorbisComment decode.Group
|
|
|
|
func init() {
|
|
registry.MustRegister(decode.Format{
|
|
Name: format.OPUS_PACKET,
|
|
Description: "Opus packet",
|
|
DecodeFn: opusDecode,
|
|
Dependencies: []decode.Dependency{
|
|
{Names: []string{format.VORBIS_COMMENT}, Group: &vorbisComment},
|
|
},
|
|
})
|
|
}
|
|
|
|
func opusDecode(d *decode.D, in any) any {
|
|
d.Endian = decode.LittleEndian
|
|
|
|
var prefix []byte
|
|
if d.BitsLeft() >= 8*8 {
|
|
prefix = d.PeekBytes(8)
|
|
}
|
|
switch {
|
|
case bytes.Equal(prefix, []byte("OpusHead")):
|
|
d.FieldValueStr("type", "head")
|
|
d.FieldUTF8("prefix", 8)
|
|
d.FieldU8("version")
|
|
channelCount := d.FieldU8("channel_count")
|
|
d.FieldU16("pre_skip")
|
|
d.FieldU32("sample_rate")
|
|
d.FieldU16("output_gain")
|
|
mapFamily := d.FieldU8("map_family")
|
|
if mapFamily != 0 {
|
|
d.FieldU8("stream_count")
|
|
d.FieldU8("coupled_count")
|
|
i := uint64(0)
|
|
d.FieldArrayLoop("channel_mappings", func() bool { return i < channelCount }, func(d *decode.D) {
|
|
d.FieldU8("channel_mapping")
|
|
})
|
|
}
|
|
case bytes.Equal(prefix, []byte("OpusTags")):
|
|
d.FieldValueStr("type", "tags")
|
|
d.FieldUTF8("prefix", 8)
|
|
d.FieldFormat("comment", vorbisComment, nil)
|
|
default:
|
|
d.FieldValueStr("type", "audio")
|
|
d.FieldStruct("toc", func(d *decode.D) {
|
|
d.FieldStruct("config", func(d *decode.D) {
|
|
configurations := map[uint64]struct {
|
|
mode string
|
|
bandwidth string
|
|
frameSize float64
|
|
}{
|
|
0: {"SILK-only", "NB", 10},
|
|
1: {"SILK-only", "NB", 20},
|
|
2: {"SILK-only", "NB", 40},
|
|
3: {"SILK-only", "NB", 60},
|
|
4: {"SILK-only", "MB", 10},
|
|
5: {"SILK-only", "MB", 20},
|
|
6: {"SILK-only", "MB", 40},
|
|
7: {"SILK-only", "MB", 60},
|
|
8: {"SILK-only", "WB", 10},
|
|
9: {"SILK-only", "WB", 20},
|
|
10: {"SILK-only", "WB", 40},
|
|
11: {"SILK-only", "WB", 60},
|
|
12: {"Hybrid", "SWB", 10},
|
|
13: {"Hybrid", "SWB", 20},
|
|
14: {"Hybrid", "FB", 10},
|
|
15: {"Hybrid", "FB", 20},
|
|
16: {"CELT-only", "NB", 2.5},
|
|
17: {"CELT-only", "NB", 5},
|
|
18: {"CELT-only", "NB", 10},
|
|
19: {"CELT-only", "NB", 20},
|
|
20: {"CELT-only", "WB", 2.5},
|
|
21: {"CELT-only", "WB", 5},
|
|
22: {"CELT-only", "WB", 10},
|
|
23: {"CELT-only", "WB", 20},
|
|
24: {"CELT-only", "SWB", 2.5},
|
|
25: {"CELT-only", "SWB", 5},
|
|
26: {"CELT-only", "SWB", 10},
|
|
27: {"CELT-only", "SWB", 20},
|
|
28: {"CELT-only", "FB", 2.5},
|
|
29: {"CELT-only", "FB", 5},
|
|
30: {"CELT-only", "FB", 10},
|
|
31: {"CELT-only", "FB", 20},
|
|
}
|
|
n := d.FieldU5("config")
|
|
config := configurations[n]
|
|
d.FieldValueStr("mode", config.mode)
|
|
d.FieldValueStr("bandwidth", config.bandwidth)
|
|
d.FieldValueFloat("frame_size", config.frameSize)
|
|
})
|
|
d.FieldBool("stereo")
|
|
d.FieldStruct("frames_per_packet", func(d *decode.D) {
|
|
framesPerPacketConfigs := map[uint64]struct {
|
|
frames uint64
|
|
mode string
|
|
}{
|
|
0: {1, "1 frame"},
|
|
1: {2, "2 frames, equal size"},
|
|
2: {2, "2 frames, different size"},
|
|
3: {0, "arbitrary number of frames"},
|
|
}
|
|
n := d.FieldU2("config")
|
|
config := framesPerPacketConfigs[n]
|
|
d.FieldValueU("frames", config.frames)
|
|
d.FieldValueStr("mode", config.mode)
|
|
})
|
|
d.FieldRawLen("data", d.BitsLeft())
|
|
})
|
|
}
|
|
|
|
return nil
|
|
}
|