mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 15:16:51 +08:00
148 lines
3.3 KiB
Go
148 lines
3.3 KiB
Go
package mpeg4audio
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
// ADTSPacket is an ADTS packet.
|
|
type ADTSPacket struct {
|
|
Type ObjectType
|
|
SampleRate int
|
|
ChannelCount int
|
|
AU []byte
|
|
}
|
|
|
|
// ADTSPackets is a group od ADTS packets.
|
|
type ADTSPackets []*ADTSPacket
|
|
|
|
// Unmarshal decodes an ADTS stream into ADTS packets.
|
|
func (ps *ADTSPackets) Unmarshal(buf []byte) error {
|
|
// refs: https://wiki.multimedia.cx/index.php/ADTS
|
|
|
|
bl := len(buf)
|
|
pos := 0
|
|
|
|
for {
|
|
if (bl - pos) < 8 {
|
|
return fmt.Errorf("invalid length")
|
|
}
|
|
|
|
syncWord := (uint16(buf[pos]) << 4) | (uint16(buf[pos+1]) >> 4)
|
|
if syncWord != 0xfff {
|
|
return fmt.Errorf("invalid syncword")
|
|
}
|
|
|
|
protectionAbsent := buf[pos+1] & 0x01
|
|
if protectionAbsent != 1 {
|
|
return fmt.Errorf("CRC is not supported")
|
|
}
|
|
|
|
pkt := &ADTSPacket{}
|
|
|
|
pkt.Type = ObjectType((buf[pos+2] >> 6) + 1)
|
|
switch pkt.Type {
|
|
case ObjectTypeAACLC:
|
|
default:
|
|
return fmt.Errorf("unsupported audio type: %d", pkt.Type)
|
|
}
|
|
|
|
sampleRateIndex := (buf[pos+2] >> 2) & 0x0F
|
|
switch {
|
|
case sampleRateIndex <= 12:
|
|
pkt.SampleRate = sampleRates[sampleRateIndex]
|
|
|
|
default:
|
|
return fmt.Errorf("invalid sample rate index: %d", sampleRateIndex)
|
|
}
|
|
|
|
channelConfig := ((buf[pos+2] & 0x01) << 2) | ((buf[pos+3] >> 6) & 0x03)
|
|
switch {
|
|
case channelConfig >= 1 && channelConfig <= 6:
|
|
pkt.ChannelCount = int(channelConfig)
|
|
|
|
case channelConfig == 7:
|
|
pkt.ChannelCount = 8
|
|
|
|
default:
|
|
return fmt.Errorf("invalid channel configuration: %d", channelConfig)
|
|
}
|
|
|
|
frameLen := int(((uint16(buf[pos+3])&0x03)<<11)|
|
|
(uint16(buf[pos+4])<<3)|
|
|
((uint16(buf[pos+5])>>5)&0x07)) - 7
|
|
if frameLen > MaxAccessUnitSize {
|
|
return fmt.Errorf("AU size (%d) is too big (maximum is %d)", frameLen, MaxAccessUnitSize)
|
|
}
|
|
|
|
frameCount := buf[pos+6] & 0x03
|
|
if frameCount != 0 {
|
|
return fmt.Errorf("frame count greater than 1 is not supported")
|
|
}
|
|
|
|
if len(buf[pos+7:]) < frameLen {
|
|
return fmt.Errorf("invalid frame length")
|
|
}
|
|
|
|
pkt.AU = buf[pos+7 : pos+7+frameLen]
|
|
pos += 7 + frameLen
|
|
|
|
*ps = append(*ps, pkt)
|
|
|
|
if (bl - pos) == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (ps ADTSPackets) marshalSize() int {
|
|
n := 0
|
|
for _, pkt := range ps {
|
|
n += 7 + len(pkt.AU)
|
|
}
|
|
return n
|
|
}
|
|
|
|
// Marshal encodes ADTS packets into an ADTS stream.
|
|
func (ps ADTSPackets) Marshal() ([]byte, error) {
|
|
buf := make([]byte, ps.marshalSize())
|
|
pos := 0
|
|
|
|
for _, pkt := range ps {
|
|
sampleRateIndex, ok := reverseSampleRates[pkt.SampleRate]
|
|
if !ok {
|
|
return nil, fmt.Errorf("invalid sample rate: %d", pkt.SampleRate)
|
|
}
|
|
|
|
var channelConfig int
|
|
switch {
|
|
case pkt.ChannelCount >= 1 && pkt.ChannelCount <= 6:
|
|
channelConfig = pkt.ChannelCount
|
|
|
|
case pkt.ChannelCount == 8:
|
|
channelConfig = 7
|
|
|
|
default:
|
|
return nil, fmt.Errorf("invalid channel count (%d)", pkt.ChannelCount)
|
|
}
|
|
|
|
frameLen := len(pkt.AU) + 7
|
|
|
|
fullness := 0x07FF // like ffmpeg does
|
|
|
|
buf[pos+0] = 0xFF
|
|
buf[pos+1] = 0xF1
|
|
buf[pos+2] = uint8((int(pkt.Type-1) << 6) | (sampleRateIndex << 2) | ((channelConfig >> 2) & 0x01))
|
|
buf[pos+3] = uint8((channelConfig&0x03)<<6 | (frameLen>>11)&0x03)
|
|
buf[pos+4] = uint8((frameLen >> 3) & 0xFF)
|
|
buf[pos+5] = uint8((frameLen&0x07)<<5 | ((fullness >> 6) & 0x1F))
|
|
buf[pos+6] = uint8((fullness & 0x3F) << 2)
|
|
pos += 7
|
|
|
|
pos += copy(buf[pos:], pkt.AU)
|
|
}
|
|
|
|
return buf, nil
|
|
}
|