Skip to content

Commit

Permalink
support MPEG-2 audio (#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 authored Jan 19, 2024
1 parent d9654f9 commit b8889df
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 204 deletions.
189 changes: 129 additions & 60 deletions pkg/codecs/mpeg1audio/frame_header.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,115 @@ import (
)

// http://www.mp3-tech.org/programmer/frame_header.html
var bitrates = map[uint8]map[uint8]int{
2: {
0b1: 32000,
0b10: 48000,
0b11: 56000,
0b100: 64000,
0b101: 80000,
0b110: 96000,
0b111: 112000,
0b1000: 128000,
0b1001: 160000,
0b1010: 192000,
0b1011: 224000,
0b1100: 256000,
0b1101: 320000,
0b1110: 384000,
var bitrates = [][][]int{
// MPEG-1
{
// layer 1
{},
// layer 2
{
32000,
48000,
56000,
64000,
80000,
96000,
112000,
128000,
160000,
192000,
224000,
256000,
320000,
384000,
},
// layer 3
{
32000,
40000,
48000,
56000,
64000,
80000,
96000,
112000,
128000,
160000,
192000,
224000,
256000,
320000,
},
},
3: {
0b1: 32000,
0b10: 40000,
0b11: 48000,
0b100: 56000,
0b101: 64000,
0b110: 80000,
0b111: 96000,
0b1000: 112000,
0b1001: 128000,
0b1010: 160000,
0b1011: 192000,
0b1100: 224000,
0b1101: 256000,
0b1110: 320000,
// MPEG-2
{
// layer 1
{},
// layer 2
{
8000,
16000,
24000,
32000,
40000,
48000,
56000,
64000,
80000,
96000,
112000,
128000,
144000,
160000,
},
// layer 3
{
8000,
16000,
24000,
32000,
40000,
48000,
56000,
64000,
80000,
96000,
112000,
128000,
144000,
160000,
},
},
}

var sampleRates = map[uint8]int{
0: 44100,
0b1: 48000,
0b10: 32000,
var sampleRates = [][]int{
// MPEG-1
{
44100,
48000,
32000,
},
// MPEG-2
{
22050,
24000,
16000,
},
}

var samplesPerFrame = [][]int{
// MPEG-1
{
384,
1152,
1152,
},
// MPEG-2
{
384,
1152,
576,
},
}

// ChannelMode is a channel mode of a MPEG-1/2 audio frame.
Expand Down Expand Up @@ -80,35 +150,38 @@ func (h *FrameHeader) Unmarshal(buf []byte) error {
}

h.MPEG2 = ((buf[1] >> 3) & 0x01) == 0
h.Layer = 4 - ((buf[1] >> 1) & 0b11)

switch {
case !h.MPEG2 && h.Layer == 2:
case !h.MPEG2 && h.Layer == 3:
default:
return fmt.Errorf("unsupported MPEG version or layer: %v %v", h.MPEG2, h.Layer)
var mpegIndex int
if h.MPEG2 {
mpegIndex = 1
} else {
mpegIndex = 0
}

h.Layer = 4 - ((buf[1] >> 1) & 0b11)
if h.Layer <= 1 || h.Layer >= 4 {
return fmt.Errorf("unsupported MPEG layer: %v", h.Layer)
}

bitrateIndex := buf[2] >> 4
var ok bool
h.Bitrate, ok = bitrates[h.Layer][bitrateIndex]
if !ok {
bitrateIndex := (buf[2] >> 4)
if bitrateIndex == 0 || bitrateIndex >= 15 {
return fmt.Errorf("invalid bitrate")
}
h.Bitrate = bitrates[mpegIndex][h.Layer-1][bitrateIndex-1]

sampleRateIndex := (buf[2] >> 2) & 0b11
h.SampleRate, ok = sampleRates[sampleRateIndex]
if !ok {
if sampleRateIndex >= 3 {
return fmt.Errorf("invalid sample rate")
}
h.SampleRate = sampleRates[mpegIndex][sampleRateIndex]

h.Padding = ((buf[2] >> 1) & 0b1) != 0
h.ChannelMode = ChannelMode(buf[3] >> 6)

return nil
}

// FrameLen returns the length of the frame associated to the header.
// FrameLen returns the length of the frame associated with the header.
func (h FrameHeader) FrameLen() int {
if h.Padding {
return (144 * h.Bitrate / h.SampleRate) + 1
Expand All @@ -118,16 +191,12 @@ func (h FrameHeader) FrameLen() int {

// SampleCount returns the number of samples contained into the frame.
func (h FrameHeader) SampleCount() int {
/*
MPEG-1:
* layer 1: 384
* layer 2: 1152
* layer 3: 1152
MPEG-2:
* layer 1: 384
* layer 2: 1152
* layer 3: 576
*/
return 1152
var mpegIndex int
if h.MPEG2 {
mpegIndex = 1
} else {
mpegIndex = 0
}

return samplesPerFrame[mpegIndex][h.Layer-1]
}
Loading

0 comments on commit b8889df

Please sign in to comment.