-
Notifications
You must be signed in to change notification settings - Fork 290
/
flac.go
151 lines (124 loc) · 3.58 KB
/
flac.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Package pcm - support raw (verbatim) PCM 16 bit in the FLAC container:
// - only 1 channel
// - only 16 bit per sample
// - only 8000, 16000, 24000, 48000 sample rate
package pcm
import (
"encoding/binary"
"unicode/utf8"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/pion/rtp"
"github.com/sigurn/crc16"
"github.com/sigurn/crc8"
)
func FLACHeader(magic bool, sampleRate uint32) []byte {
b := make([]byte, 42)
if magic {
copy(b, "fLaC") // [0..3]
}
// https://xiph.org/flac/format.html#metadata_block_header
b[4] = 0x80 // [4] lastMetadata=1 (1 bit), blockType=0 - STREAMINFO (7 bit)
b[7] = 0x22 // [5..7] blockLength=34 (24 bit)
// Important for Apple QuickTime player:
// 1. Both values should be same
// 2. Maximum value = 32768
binary.BigEndian.PutUint16(b[8:], 32768) // [8..9] info.BlockSizeMin=16 (16 bit)
binary.BigEndian.PutUint16(b[10:], 32768) // [10..11] info.BlockSizeMin=65535 (16 bit)
// [12..14] info.FrameSizeMin=0 (24 bit)
// [15..17] info.FrameSizeMax=0 (24 bit)
b[18] = byte(sampleRate >> 12)
b[19] = byte(sampleRate >> 4)
b[20] = byte(sampleRate << 4) // [18..20] info.SampleRate=8000 (20 bit), info.NChannels=1-1 (3 bit)
b[21] = 0xF0 // [21..25] info.BitsPerSample=16-1 (5 bit), info.NSamples (36 bit)
// [26..41] MD5sum (16 bytes)
return b
}
var table8 *crc8.Table
var table16 *crc16.Table
func FLACEncoder(codecName string, clockRate uint32, handler core.HandlerFunc) core.HandlerFunc {
var sr byte
switch clockRate {
case 8000:
sr = 0b0100
case 16000:
sr = 0b0101
case 22050:
sr = 0b0110
case 24000:
sr = 0b0111
case 32000:
sr = 0b1000
case 44100:
sr = 0b1001
case 48000:
sr = 0b1010
case 96000:
sr = 0b1011
default:
return nil
}
if table8 == nil {
table8 = crc8.MakeTable(crc8.CRC8)
}
if table16 == nil {
table16 = crc16.MakeTable(crc16.CRC16_BUYPASS)
}
var sampleNumber int32
return func(packet *rtp.Packet) {
samples := uint16(len(packet.Payload))
if codecName == core.CodecPCM || codecName == core.CodecPCML {
samples /= 2
}
// https://xiph.org/flac/format.html#frame_header
buf := make([]byte, samples*2+30)
// 1. Frame header
buf[0] = 0xFF
buf[1] = 0xF9 // [0..1] syncCode=0xFFF8 - reserved (15 bit), blockStrategy=1 - variable-blocksize (1 bit)
buf[2] = 0x70 | sr // blockSizeType=7 (4 bit), sampleRate=4 - 8000 (4 bit)
buf[3] = 0x08 // channels=1-1 (4 bit), sampleSize=4 - 16 (3 bit), reserved=0 (1 bit)
n := 4 + utf8.EncodeRune(buf[4:], sampleNumber) // 4 bytes max
sampleNumber += int32(samples)
// this is wrong but very simple frame block size value
binary.BigEndian.PutUint16(buf[n:], samples-1)
n += 2
buf[n] = crc8.Checksum(buf[:n], table8)
n += 1
// 2. Subframe header
buf[n] = 0x02 // padding=0 (1 bit), subframeType=1 - verbatim (6 bit), wastedFlag=0 (1 bit)
n += 1
// 3. Subframe
switch codecName {
case core.CodecPCMA:
for _, b := range packet.Payload {
s16 := PCMAtoPCM(b)
buf[n] = byte(s16 >> 8)
buf[n+1] = byte(s16)
n += 2
}
case core.CodecPCMU:
for _, b := range packet.Payload {
s16 := PCMUtoPCM(b)
buf[n] = byte(s16 >> 8)
buf[n+1] = byte(s16)
n += 2
}
case core.CodecPCM:
n += copy(buf[n:], packet.Payload)
case core.CodecPCML:
// reverse endian from little to big
size := len(packet.Payload)
for i := 0; i < size; i += 2 {
buf[n] = packet.Payload[i+1]
buf[n+1] = packet.Payload[i]
n += 2
}
}
// 4. Frame footer
crc := crc16.Checksum(buf[:n], table16)
binary.BigEndian.PutUint16(buf[n:], crc)
n += 2
clone := *packet
clone.Payload = buf[:n]
handler(&clone)
}
}