123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- 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) {
- // In very rare cases noname cameras may send data not according to the standard
- // https://github.com/AlexxIT/go2rtc/issues/1328
- if IsADTS(packet.Payload) {
- clone := *packet
- clone.Version = RTPPacketVersionAAC
- clone.Timestamp = timestamp
- clone.Payload = clone.Payload[ADTSHeaderSize:]
- handler(&clone)
- }
- 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:])
- }
|