install go2rtc on bob
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package aac
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/AlexxIT/go2rtc/pkg/bits"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/pion/rtp"
|
||||
)
|
||||
|
||||
const ADTSHeaderSize = 7
|
||||
|
||||
func ADTSHeaderLen(b []byte) int {
|
||||
if HasCRC(b) {
|
||||
return 9 // 7 bytes header + 2 bytes CRC
|
||||
}
|
||||
return ADTSHeaderSize
|
||||
}
|
||||
|
||||
func IsADTS(b []byte) bool {
|
||||
// AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP (QQQQQQQQ QQQQQQQQ)
|
||||
// A 12 Syncword, all bits must be set to 1.
|
||||
// C 2 Layer, always set to 0.
|
||||
return len(b) >= ADTSHeaderSize && b[0] == 0xFF && b[1]&0b1111_0110 == 0xF0
|
||||
}
|
||||
|
||||
func HasCRC(b []byte) bool {
|
||||
// AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP (QQQQQQQQ QQQQQQQQ)
|
||||
// D 1 Protection absence, set to 1 if there is no CRC and 0 if there is CRC.
|
||||
return b[1]&0b1 == 0
|
||||
}
|
||||
|
||||
func ADTSToCodec(b []byte) *core.Codec {
|
||||
// 1. Check ADTS header
|
||||
if !IsADTS(b) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 2. Decode ADTS params
|
||||
// https://wiki.multimedia.cx/index.php/ADTS
|
||||
rd := bits.NewReader(b)
|
||||
_ = rd.ReadBits(12) // Syncword, all bits must be set to 1
|
||||
_ = rd.ReadBit() // MPEG Version, set to 0 for MPEG-4 and 1 for MPEG-2
|
||||
_ = rd.ReadBits(2) // Layer, always set to 0
|
||||
_ = rd.ReadBit() // Protection absence, set to 1 if there is no CRC and 0 if there is CRC
|
||||
objType := rd.ReadBits8(2) + 1 // Profile, the MPEG-4 Audio Object Type minus 1
|
||||
sampleRateIdx := rd.ReadBits8(4) // MPEG-4 Sampling Frequency Index
|
||||
_ = rd.ReadBit() // Private bit, guaranteed never to be used by MPEG, set to 0 when encoding, ignore when decoding
|
||||
channels := rd.ReadBits8(3) // MPEG-4 Channel Configuration
|
||||
|
||||
//_ = rd.ReadBit() // Originality, set to 1 to signal originality of the audio and 0 otherwise
|
||||
//_ = rd.ReadBit() // Home, set to 1 to signal home usage of the audio and 0 otherwise
|
||||
//_ = rd.ReadBit() // Copyright ID bit
|
||||
//_ = rd.ReadBit() // Copyright ID start
|
||||
//_ = rd.ReadBits(13) // Frame length
|
||||
//_ = rd.ReadBits(11) // Buffer fullness
|
||||
//_ = rd.ReadBits(2) // Number of AAC frames (Raw Data Blocks) in ADTS frame minus 1
|
||||
//_ = rd.ReadBits(16) // CRC check
|
||||
|
||||
// 3. Encode RTP config
|
||||
wr := bits.NewWriter(nil)
|
||||
wr.WriteBits8(objType, 5)
|
||||
wr.WriteBits8(sampleRateIdx, 4)
|
||||
wr.WriteBits8(channels, 4)
|
||||
conf := wr.Bytes()
|
||||
|
||||
codec := &core.Codec{
|
||||
Name: core.CodecAAC,
|
||||
ClockRate: sampleRates[sampleRateIdx],
|
||||
Channels: channels,
|
||||
FmtpLine: FMTP + hex.EncodeToString(conf),
|
||||
}
|
||||
return codec
|
||||
}
|
||||
|
||||
func ReadADTSSize(b []byte) uint16 {
|
||||
// AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP (QQQQQQQQ QQQQQQQQ)
|
||||
_ = b[5] // bounds
|
||||
return uint16(b[3]&0b11)<<11 | uint16(b[4])<<3 | uint16(b[5]>>5)
|
||||
}
|
||||
|
||||
func WriteADTSSize(b []byte, size uint16) {
|
||||
// AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP (QQQQQQQQ QQQQQQQQ)
|
||||
_ = b[5] // bounds
|
||||
b[3] |= byte(size >> (8 + 3))
|
||||
b[4] = byte(size >> 3)
|
||||
b[5] |= byte(size << 5)
|
||||
return
|
||||
}
|
||||
|
||||
func ADTSTimeSize(b []byte) uint32 {
|
||||
var units uint32
|
||||
for len(b) > ADTSHeaderSize {
|
||||
auSize := ReadADTSSize(b)
|
||||
b = b[auSize:]
|
||||
units++
|
||||
}
|
||||
return units * AUTime
|
||||
}
|
||||
|
||||
func CodecToADTS(codec *core.Codec) []byte {
|
||||
s := core.Between(codec.FmtpLine, "config=", ";")
|
||||
conf, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
objType, sampleFreqIdx, channels, _ := DecodeConfig(conf)
|
||||
profile := objType - 1
|
||||
|
||||
wr := bits.NewWriter(nil)
|
||||
wr.WriteAllBits(1, 12) // Syncword, all bits must be set to 1
|
||||
wr.WriteBit(0) // MPEG Version, set to 0 for MPEG-4 and 1 for MPEG-2
|
||||
wr.WriteBits8(0, 2) // Layer, always set to 0
|
||||
wr.WriteBit(1) // Protection absence, set to 1 if there is no CRC and 0 if there is CRC
|
||||
wr.WriteBits8(profile, 2) // Profile, the MPEG-4 Audio Object Type minus 1
|
||||
wr.WriteBits8(sampleFreqIdx, 4) // MPEG-4 Sampling Frequency Index
|
||||
wr.WriteBit(0) // Private bit, guaranteed never to be used by MPEG, set to 0 when encoding, ignore when decoding
|
||||
wr.WriteBits8(channels, 3) // MPEG-4 Channel Configuration
|
||||
wr.WriteBit(0) // Originality, set to 1 to signal originality of the audio and 0 otherwise
|
||||
wr.WriteBit(0) // Home, set to 1 to signal home usage of the audio and 0 otherwise
|
||||
wr.WriteBit(0) // Copyright ID bit
|
||||
wr.WriteBit(0) // Copyright ID start
|
||||
wr.WriteBits16(0, 13) // Frame length
|
||||
wr.WriteAllBits(1, 11) // Buffer fullness (variable bitrate)
|
||||
wr.WriteBits8(0, 2) // Number of AAC frames (Raw Data Blocks) in ADTS frame minus 1
|
||||
|
||||
return wr.Bytes()
|
||||
}
|
||||
|
||||
func EncodeToADTS(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
|
||||
adts := CodecToADTS(codec)
|
||||
|
||||
return func(packet *rtp.Packet) {
|
||||
if !IsADTS(packet.Payload) {
|
||||
b := make([]byte, ADTSHeaderSize+len(packet.Payload))
|
||||
copy(b, adts)
|
||||
copy(b[ADTSHeaderSize:], packet.Payload)
|
||||
WriteADTSSize(b, uint16(len(b)))
|
||||
|
||||
clone := *packet
|
||||
clone.Payload = b
|
||||
handler(&clone)
|
||||
} else {
|
||||
handler(packet)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user