mirror of
https://github.com/bluenviron/mediamtx
synced 2025-01-21 14:33:36 +00:00
192 lines
3.9 KiB
Go
192 lines
3.9 KiB
Go
package aac
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
// ADTSPacket is an ADTS packet
|
|
type ADTSPacket struct {
|
|
SampleRate int
|
|
ChannelCount int
|
|
Frame []byte
|
|
}
|
|
|
|
// DecodeADTS decodes an ADTS stream into ADTS packets.
|
|
func DecodeADTS(byts []byte) ([]*ADTSPacket, error) {
|
|
// refs: https://wiki.multimedia.cx/index.php/ADTS
|
|
|
|
var ret []*ADTSPacket
|
|
|
|
for len(byts) > 0 {
|
|
syncWord := (uint16(byts[0]) << 4) | (uint16(byts[1]) >> 4)
|
|
if syncWord != 0xfff {
|
|
return nil, fmt.Errorf("invalid syncword")
|
|
}
|
|
|
|
protectionAbsent := byts[1] & 0x01
|
|
if protectionAbsent != 1 {
|
|
return nil, fmt.Errorf("ADTS with CRC is not supported")
|
|
}
|
|
|
|
pkt := &ADTSPacket{}
|
|
|
|
profile := (byts[2] >> 6)
|
|
if profile != 0 {
|
|
return nil, fmt.Errorf("only AAC-LC is supported")
|
|
}
|
|
|
|
sampleRateIndex := (byts[2] >> 2) & 0x0F
|
|
switch sampleRateIndex {
|
|
case 0:
|
|
pkt.SampleRate = 96000
|
|
case 1:
|
|
pkt.SampleRate = 88200
|
|
case 2:
|
|
pkt.SampleRate = 64000
|
|
case 3:
|
|
pkt.SampleRate = 48000
|
|
case 4:
|
|
pkt.SampleRate = 44100
|
|
case 5:
|
|
pkt.SampleRate = 32000
|
|
case 6:
|
|
pkt.SampleRate = 24000
|
|
case 7:
|
|
pkt.SampleRate = 22050
|
|
case 8:
|
|
pkt.SampleRate = 16000
|
|
case 9:
|
|
pkt.SampleRate = 12000
|
|
case 10:
|
|
pkt.SampleRate = 11025
|
|
case 11:
|
|
pkt.SampleRate = 8000
|
|
case 12:
|
|
pkt.SampleRate = 7350
|
|
default:
|
|
return nil, fmt.Errorf("invalid sample rate index: %d", sampleRateIndex)
|
|
}
|
|
|
|
channelConfig := ((byts[2] & 0x01) << 2) | ((byts[3] >> 6) & 0x03)
|
|
switch channelConfig {
|
|
case 1:
|
|
pkt.ChannelCount = 1
|
|
case 2:
|
|
pkt.ChannelCount = 2
|
|
case 3:
|
|
pkt.ChannelCount = 3
|
|
case 4:
|
|
pkt.ChannelCount = 4
|
|
case 5:
|
|
pkt.ChannelCount = 5
|
|
case 6:
|
|
pkt.ChannelCount = 6
|
|
case 7:
|
|
pkt.ChannelCount = 8
|
|
default:
|
|
return nil, fmt.Errorf("invalid channel configuration: %d", channelConfig)
|
|
}
|
|
|
|
frameLen := int(((uint16(byts[3])&0x03)<<11)|
|
|
(uint16(byts[4])<<3)|
|
|
((uint16(byts[5])>>5)&0x07)) - 7
|
|
|
|
fullness := ((uint16(byts[5]) & 0x1F) << 6) | ((uint16(byts[6]) >> 2) & 0x3F)
|
|
if fullness != 1800 {
|
|
return nil, fmt.Errorf("fullness not supported")
|
|
}
|
|
|
|
frameCount := byts[6] & 0x03
|
|
if frameCount != 0 {
|
|
return nil, fmt.Errorf("multiple frame count not supported")
|
|
}
|
|
|
|
if len(byts[7:]) < frameLen {
|
|
return nil, fmt.Errorf("invalid frame length")
|
|
}
|
|
|
|
pkt.Frame = byts[7 : 7+frameLen]
|
|
byts = byts[7+frameLen:]
|
|
|
|
ret = append(ret, pkt)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
// EncodeADTS encodes ADTS packets into an ADTS stream.
|
|
func EncodeADTS(pkts []*ADTSPacket) ([]byte, error) {
|
|
var ret []byte
|
|
|
|
for _, pkt := range pkts {
|
|
frameLen := len(pkt.Frame) + 7
|
|
fullness := 1800
|
|
|
|
var channelConf uint8
|
|
switch pkt.ChannelCount {
|
|
case 1:
|
|
channelConf = 1
|
|
case 2:
|
|
channelConf = 2
|
|
case 3:
|
|
channelConf = 3
|
|
case 4:
|
|
channelConf = 4
|
|
case 5:
|
|
channelConf = 5
|
|
case 6:
|
|
channelConf = 6
|
|
case 8:
|
|
channelConf = 7
|
|
default:
|
|
return nil, fmt.Errorf("invalid channel count: %v", pkt.ChannelCount)
|
|
}
|
|
|
|
var sampleRateIndex uint8
|
|
switch pkt.SampleRate {
|
|
case 96000:
|
|
sampleRateIndex = 0
|
|
case 88200:
|
|
sampleRateIndex = 1
|
|
case 64000:
|
|
sampleRateIndex = 2
|
|
case 48000:
|
|
sampleRateIndex = 3
|
|
case 44100:
|
|
sampleRateIndex = 4
|
|
case 32000:
|
|
sampleRateIndex = 5
|
|
case 24000:
|
|
sampleRateIndex = 6
|
|
case 22050:
|
|
sampleRateIndex = 7
|
|
case 16000:
|
|
sampleRateIndex = 8
|
|
case 12000:
|
|
sampleRateIndex = 9
|
|
case 11025:
|
|
sampleRateIndex = 10
|
|
case 8000:
|
|
sampleRateIndex = 11
|
|
case 7350:
|
|
sampleRateIndex = 12
|
|
default:
|
|
return nil, fmt.Errorf("invalid sample rate: %v", pkt.SampleRate)
|
|
}
|
|
|
|
header := make([]byte, 7)
|
|
header[0] = 0xFF
|
|
header[1] = 0xF1
|
|
header[2] = (sampleRateIndex << 2) | ((channelConf >> 2) & 0x01)
|
|
header[3] = (channelConf&0x03)<<6 | uint8((frameLen>>11)&0x03)
|
|
header[4] = uint8((frameLen >> 3) & 0xFF)
|
|
header[5] = uint8((frameLen&0x07)<<5 | ((fullness >> 6) & 0x1F))
|
|
header[6] = uint8((fullness & 0x3F) << 2)
|
|
ret = append(ret, header...)
|
|
|
|
ret = append(ret, pkt.Frame...)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|