-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathheader.go
184 lines (157 loc) · 4.13 KB
/
header.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package mp3
import (
"fmt"
"time"
)
type (
Version byte
Layer byte
ChannelMode byte
Emphasis byte
FrameHeader struct {
Version Version
Layer Layer
Protection bool
Bitrate int
SampleRate int
Pad bool
Private bool
ChannelMode ChannelMode
IntensityStereo bool
MSStereo bool
CopyRight bool
Original bool
Emphasis Emphasis
Size int64
Samples int
Duration time.Duration
}
)
const (
MPEG25 Version = iota
MPEGReserved
MPEG2
MPEG1
)
const (
LayerReserved Layer = iota
Layer3
Layer2
Layer1
)
const (
EmphNone Emphasis = iota
Emph5015
EmphReserved
EmphCCITJ17
)
const (
Stereo ChannelMode = iota
JointStereo
DualChannel
SingleChannel
)
var (
bitrates = map[Version]map[Layer][15]int{
MPEG1: { // MPEG 1
Layer1: {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}, // Layer1
Layer2: {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384}, // Layer2
Layer3: {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320}, // Layer3
},
MPEG2: { // MPEG 2, 2.5
Layer1: {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}, // Layer1
Layer2: {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, // Layer2
Layer3: {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, // Layer3
},
}
sampleRates = map[Version][3]int{
MPEG1: {44100, 48000, 32000},
MPEG2: {22050, 24000, 16000},
MPEG25: {11025, 12000, 8000},
MPEGReserved: {0, 0, 0},
}
samplesPerFrame = map[Version]map[Layer]int{
MPEG1: {
Layer1: 384,
Layer2: 1152,
Layer3: 1152,
},
MPEG2: {
Layer1: 384,
Layer2: 1152,
Layer3: 576,
},
}
slotSize = map[Layer]int{
LayerReserved: 0,
Layer3: 1,
Layer2: 1,
Layer1: 4,
}
)
func init() {
bitrates[MPEG25] = bitrates[MPEG2]
samplesPerFrame[MPEG25] = samplesPerFrame[MPEG2]
}
func (this *FrameHeader) Parse(bs []byte) error {
this.Size = 0
this.Samples = 0
this.Duration = 0
if len(bs) < 4 {
return fmt.Errorf("not enough bytes")
}
if bs[0] != 0xFF || (bs[1]&0xE0) != 0xE0 {
return fmt.Errorf("missing sync word, got: %x, %x", bs[0], bs[1])
}
this.Version = Version((bs[1] >> 3) & 0x03)
if this.Version == MPEGReserved {
return fmt.Errorf("reserved mpeg version")
}
this.Layer = Layer(((bs[1] >> 1) & 0x03))
if this.Layer == LayerReserved {
return fmt.Errorf("reserved layer")
}
this.Protection = (bs[1] & 0x01) != 0x01
bitrateIdx := (bs[2] >> 4) & 0x0F
if bitrateIdx == 0x0F {
return fmt.Errorf("invalid bitrate: %v", bitrateIdx)
}
this.Bitrate = bitrates[this.Version][this.Layer][bitrateIdx] * 1000
if this.Bitrate == 0 {
return fmt.Errorf("invalid bitrate: %v", bitrateIdx)
}
sampleRateIdx := (bs[2] >> 2) & 0x03
if sampleRateIdx == 0x03 {
return fmt.Errorf("invalid sample rate: %v", sampleRateIdx)
}
this.SampleRate = sampleRates[this.Version][sampleRateIdx]
this.Pad = ((bs[2] >> 1) & 0x01) == 0x01
this.Private = (bs[2] & 0x01) == 0x01
this.ChannelMode = ChannelMode(bs[3]>>6) & 0x03
// todo: mode extension
this.CopyRight = (bs[3]>>3)&0x01 == 0x01
this.Original = (bs[3]>>2)&0x01 == 0x01
this.Emphasis = Emphasis(bs[3] & 0x03)
if this.Emphasis == EmphReserved {
return fmt.Errorf("reserved emphasis")
}
this.Size = this.size()
this.Samples = this.samples()
this.Duration = this.duration()
return nil
}
func (this *FrameHeader) samples() int {
return samplesPerFrame[this.Version][this.Layer]
}
func (this *FrameHeader) size() int64 {
bps := float64(this.samples()) / 8
fsize := (bps * float64(this.Bitrate)) / float64(this.SampleRate)
if this.Pad {
fsize += float64(slotSize[this.Layer])
}
return int64(fsize)
}
func (this *FrameHeader) duration() time.Duration {
ms := (1000 / float64(this.SampleRate)) * float64(this.samples())
return time.Duration(time.Duration(float64(time.Millisecond) * ms))
}