mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-10-06 00:37:00 +08:00
143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
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
|
|
|
|
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)
|
|
|
|
if len(packet.Payload) < int(2+headersSize) {
|
|
return
|
|
}
|
|
|
|
headers := packet.Payload[2 : 2+headersSize]
|
|
units := packet.Payload[2+headersSize:]
|
|
|
|
for len(headers) >= 2 {
|
|
unitSize := binary.BigEndian.Uint16(headers) >> 3
|
|
|
|
if len(units) < int(unitSize) {
|
|
return
|
|
}
|
|
|
|
unit := units[:unitSize]
|
|
|
|
headers = headers[2:]
|
|
units = units[unitSize:]
|
|
|
|
timestamp += AUTime
|
|
|
|
clone := *packet
|
|
clone.Version = RTPPacketVersionAAC
|
|
clone.Timestamp = timestamp
|
|
if IsADTS(unit) {
|
|
clone.Payload = unit[ADTSHeaderSize:]
|
|
} else {
|
|
clone.Payload = unit
|
|
}
|
|
handler(&clone)
|
|
}
|
|
}
|
|
}
|
|
|
|
func RTPPay(handler core.HandlerFunc) core.HandlerFunc {
|
|
sequencer := rtp.NewRandomSequencer()
|
|
|
|
return func(packet *rtp.Packet) {
|
|
if packet.Version != RTPPacketVersionAAC {
|
|
handler(packet)
|
|
return
|
|
}
|
|
|
|
// support ONLY one unit in payload
|
|
auSize := uint16(len(packet.Payload))
|
|
// 2 bytes header size + 2 bytes first payload size
|
|
payload := make([]byte, 2+2+auSize)
|
|
payload[1] = 16 // header size in bits
|
|
binary.BigEndian.PutUint16(payload[2:], auSize<<3)
|
|
copy(payload[4:], packet.Payload)
|
|
|
|
clone := rtp.Packet{
|
|
Header: rtp.Header{
|
|
Version: 2,
|
|
Marker: true,
|
|
SequenceNumber: sequencer.NextSequenceNumber(),
|
|
Timestamp: packet.Timestamp,
|
|
},
|
|
Payload: payload,
|
|
}
|
|
handler(&clone)
|
|
}
|
|
}
|
|
|
|
func ADTStoRTP(src []byte) (dst []byte) {
|
|
dst = make([]byte, 2) // header bytes
|
|
for i, n := 0, len(src)-ADTSHeaderSize; i < n; {
|
|
auSize := ReadADTSSize(src[i:])
|
|
dst = append(dst, byte(auSize>>5), byte(auSize<<3)) // size in bits
|
|
i += int(auSize)
|
|
}
|
|
hdrSize := uint16(len(dst) - 2)
|
|
binary.BigEndian.PutUint16(dst, hdrSize<<3) // size in bits
|
|
return append(dst, src...)
|
|
}
|
|
|
|
func RTPTimeSize(b []byte) uint32 {
|
|
// convert RTP header size to units count
|
|
units := binary.BigEndian.Uint16(b) >> 4
|
|
return uint32(units) * AUTime
|
|
}
|
|
|
|
func RTPToADTS(codec *core.Codec, handler core.HandlerFunc) core.HandlerFunc {
|
|
adts := CodecToADTS(codec)
|
|
|
|
return func(packet *rtp.Packet) {
|
|
src := packet.Payload
|
|
dst := make([]byte, 0, len(src))
|
|
|
|
headersSize := binary.BigEndian.Uint16(src) >> 3
|
|
headers := src[2 : 2+headersSize]
|
|
units := src[2+headersSize:]
|
|
|
|
for len(headers) > 0 {
|
|
unitSize := binary.BigEndian.Uint16(headers) >> 3
|
|
headers = headers[2:]
|
|
unit := units[:unitSize]
|
|
units = units[unitSize:]
|
|
|
|
if !IsADTS(unit) {
|
|
i := len(dst)
|
|
dst = append(dst, adts...)
|
|
WriteADTSSize(dst[i:], ADTSHeaderSize+uint16(len(unit)))
|
|
}
|
|
|
|
dst = append(dst, unit...)
|
|
}
|
|
|
|
clone := *packet
|
|
clone.Version = RTPPacketVersionAAC
|
|
clone.Payload = dst
|
|
handler(&clone)
|
|
}
|
|
}
|
|
|
|
func RTPToCodec(b []byte) *core.Codec {
|
|
hdrSize := binary.BigEndian.Uint16(b) / 8
|
|
return ADTSToCodec(b[2+hdrSize:])
|
|
}
|