Rewrite support MPEG-TS client

This commit is contained in:
Alexey Khit
2023-08-17 05:41:27 +03:00
parent 4a82eb3503
commit b3def6cfa2
11 changed files with 569 additions and 367 deletions
+6 -3
View File
@@ -17,7 +17,10 @@ const (
// streamtype=5 - audio stream
const fmtp = "streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config="
var sampleRates = []uint32{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350}
var sampleRates = []uint32{
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350,
0, 0, 0, // protection from request sampleRates[15]
}
func ConfigToCodec(conf []byte) *core.Codec {
// https://en.wikipedia.org/wiki/MPEG-4_Part_3#MPEG-4_Audio_Object_Types
@@ -40,9 +43,9 @@ func ConfigToCodec(conf []byte) *core.Codec {
codec.Name = fmt.Sprintf("AAC-%X", objType)
}
if sampleRateIdx := rd.ReadBits8(4); sampleRateIdx < 12 {
if sampleRateIdx := rd.ReadBits8(4); sampleRateIdx < 0x0F {
codec.ClockRate = sampleRates[sampleRateIdx]
} else if sampleRateIdx == 0x0F {
} else {
codec.ClockRate = rd.ReadBits(24)
}
+61
View File
@@ -0,0 +1,61 @@
package aac
import (
"encoding/hex"
"github.com/AlexxIT/go2rtc/pkg/bits"
"github.com/AlexxIT/go2rtc/pkg/core"
)
func IsADTS(b []byte) bool {
_ = b[1]
return len(b) > 7 && b[0] == 0xFF && b[1]&0xF0 == 0xF0
}
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.ReadBits16(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()
wr.WriteBits8(objType, 5)
wr.WriteBits8(sampleRateIdx, 4)
wr.WriteBits16(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)
return uint16(b[3]&0x03)<<(8+3) | uint16(b[4])<<3 | uint16(b[5]>>5)
}
+22 -6
View File
@@ -2,11 +2,13 @@ package aac
import (
"encoding/binary"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/pion/rtp"
)
const RTPPacketVersionAAC = 0
const ADTSHeaderSize = 7
func RTPDepay(handler core.HandlerFunc) core.HandlerFunc {
var timestamp uint32
@@ -14,6 +16,7 @@ func RTPDepay(handler core.HandlerFunc) core.HandlerFunc {
return func(packet *rtp.Packet) {
// support ONLY 2 bytes header size!
// streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1408
// https://datatracker.ietf.org/doc/html/rfc3640
headersSize := binary.BigEndian.Uint16(packet.Payload) >> 3
//log.Printf("[RTP/AAC] units: %d, size: %4d, ts: %10d, %t", headersSize/2, len(packet.Payload), packet.Timestamp, packet.Marker)
@@ -35,7 +38,7 @@ func RTPDepay(handler core.HandlerFunc) core.HandlerFunc {
clone.Version = RTPPacketVersionAAC
clone.Timestamp = timestamp
if IsADTS(unit) {
clone.Payload = unit[7:]
clone.Payload = unit[ADTSHeaderSize:]
} else {
clone.Payload = unit
}
@@ -54,11 +57,11 @@ func RTPPay(handler core.HandlerFunc) core.HandlerFunc {
}
// support ONLY one unit in payload
size := uint16(len(packet.Payload))
auSize := uint16(len(packet.Payload))
// 2 bytes header size + 2 bytes first payload size
payload := make([]byte, 2+2+size)
payload := make([]byte, 2+2+auSize)
payload[1] = 16 // header size in bits
binary.BigEndian.PutUint16(payload[2:], size<<3)
binary.BigEndian.PutUint16(payload[2:], auSize<<3)
copy(payload[4:], packet.Payload)
clone := rtp.Packet{
@@ -74,6 +77,19 @@ func RTPPay(handler core.HandlerFunc) core.HandlerFunc {
}
}
func IsADTS(b []byte) bool {
return len(b) > 7 && b[0] == 0xFF && b[1]&0xF0 == 0xF0
func ADTStoRTP(b []byte) []byte {
header := make([]byte, 2)
for i := 0; i < len(b); {
auSize := ReadADTSSize(b[i:])
header = append(header, byte(auSize>>5), byte(auSize<<3)) // size in bits
i += int(auSize)
}
hdrSize := uint16(len(header) - 2)
binary.BigEndian.PutUint16(header, hdrSize<<3) // size in bits
return append(header, b...)
}
func RTPToCodec(b []byte) *core.Codec {
hdrSize := binary.BigEndian.Uint16(b) / 8
return ADTSToCodec(b[2+hdrSize:])
}