|
|
// Copyright 2020, Chef. All rights reserved.
|
|
|
// https://github.com/q191201771/lal
|
|
|
//
|
|
|
// Use of this source code is governed by a MIT-style license
|
|
|
// that can be found in the License file.
|
|
|
//
|
|
|
// Author: Chef (191201771@qq.com)
|
|
|
|
|
|
package rtprtcp
|
|
|
|
|
|
import (
|
|
|
"github.com/q191201771/lal/pkg/base"
|
|
|
)
|
|
|
|
|
|
type RtpUnpackerAac struct {
|
|
|
payloadType base.AvPacketPt
|
|
|
clockRate int
|
|
|
onAvPacket OnAvPacket
|
|
|
}
|
|
|
|
|
|
func NewRtpUnpackerAac(payloadType base.AvPacketPt, clockRate int, onAvPacket OnAvPacket) *RtpUnpackerAac {
|
|
|
return &RtpUnpackerAac{
|
|
|
payloadType: payloadType,
|
|
|
clockRate: clockRate,
|
|
|
onAvPacket: onAvPacket,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (unpacker *RtpUnpackerAac) CalcPositionIfNeeded(pkt *RtpPacket) {
|
|
|
// noop
|
|
|
}
|
|
|
|
|
|
func (unpacker *RtpUnpackerAac) TryUnpackOne(list *RtpPacketList) (unpackedFlag bool, unpackedSeq uint16) {
|
|
|
// rfc3640 2.11. Global Structure of Payload Format
|
|
|
//
|
|
|
// +---------+-----------+-----------+---------------+
|
|
|
// | RTP | AU Header | Auxiliary | Access Unit |
|
|
|
// | Header | Section | Section | Data Section |
|
|
|
// +---------+-----------+-----------+---------------+
|
|
|
//
|
|
|
// <----------RTP Packet Payload----------->
|
|
|
//
|
|
|
// rfc3640 3.2.1. The AU Header Section
|
|
|
//
|
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
|
|
|
// |AU-headers-length|AU-header|AU-header| |AU-header|padding|
|
|
|
// | | (1) | (2) | | (n) | bits |
|
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
|
|
|
//
|
|
|
// rfc3640 3.3.6. High Bit-rate AAC
|
|
|
//
|
|
|
// rtp_parse_mp4_au()
|
|
|
//
|
|
|
//
|
|
|
// 3.2.3.1. Fragmentation
|
|
|
//
|
|
|
// A packet SHALL carry either one or more complete Access Units, or a
|
|
|
// single fragment of an Access Unit. Fragments of the same Access Unit
|
|
|
// have the same time stamp but different RTP sequence numbers. The
|
|
|
// marker bit in the RTP header is 1 on the last fragment of an Access
|
|
|
// Unit, and 0 on all other fragments.
|
|
|
//
|
|
|
|
|
|
p := list.Head.Next // first
|
|
|
if p == nil {
|
|
|
return false, 0
|
|
|
}
|
|
|
b := p.Packet.Body()
|
|
|
|
|
|
aus := parseAu(b)
|
|
|
|
|
|
// 只有一个描述
|
|
|
if len(aus) == 1 {
|
|
|
|
|
|
// 描述的音频帧完整的在当前的rtp packet中,没有跨越到下个rtp packet
|
|
|
if aus[0].size <= uint32(len(b[aus[0].pos:])) {
|
|
|
// one complete access unit
|
|
|
var outPkt base.AvPacket
|
|
|
outPkt.PayloadType = unpacker.payloadType
|
|
|
outPkt.Timestamp = int64(p.Packet.Header.Timestamp / uint32(unpacker.clockRate/1000))
|
|
|
outPkt.Payload = b[aus[0].pos : aus[0].pos+aus[0].size]
|
|
|
unpacker.onAvPacket(outPkt)
|
|
|
|
|
|
list.Head.Next = p.Next
|
|
|
list.Size--
|
|
|
return true, p.Packet.Header.Seq
|
|
|
}
|
|
|
|
|
|
// fragmented
|
|
|
// 注意,这里我们参考size和rtp包头中的timestamp,不参考rtp包头中的mark位
|
|
|
|
|
|
totalSize := aus[0].size
|
|
|
timestamp := p.Packet.Header.Timestamp
|
|
|
|
|
|
var as [][]byte
|
|
|
as = append(as, b[aus[0].pos:])
|
|
|
cacheSize := uint32(len(b[aus[0].pos:]))
|
|
|
|
|
|
seq := p.Packet.Header.Seq
|
|
|
p = p.Next
|
|
|
packetCount := 0
|
|
|
for {
|
|
|
packetCount++
|
|
|
if p == nil {
|
|
|
return false, 0
|
|
|
}
|
|
|
if SubSeq(p.Packet.Header.Seq, seq) != 1 {
|
|
|
return false, 0
|
|
|
}
|
|
|
if p.Packet.Header.Timestamp != timestamp {
|
|
|
Log.Errorf("fragments of the same access shall have the same timestamp. first=%d, curr=%d",
|
|
|
timestamp, p.Packet.Header.Timestamp)
|
|
|
return false, 0
|
|
|
}
|
|
|
|
|
|
// 注意,非第一个fragment,也会包含au,au的size和第一个fragment里au的size应该相等
|
|
|
b = p.Packet.Body()
|
|
|
aus := parseAu(b)
|
|
|
if len(aus) != 1 {
|
|
|
Log.Errorf("shall be a single fragment. len(aus)=%d", len(aus))
|
|
|
return false, 0
|
|
|
}
|
|
|
if aus[0].size != totalSize {
|
|
|
Log.Errorf("fragments of the same access shall have the same size. first=%d, curr=%d",
|
|
|
totalSize, aus[0].size)
|
|
|
return false, 0
|
|
|
}
|
|
|
|
|
|
cacheSize += uint32(len(b[aus[0].pos:]))
|
|
|
seq = p.Packet.Header.Seq
|
|
|
as = append(as, b[aus[0].pos:])
|
|
|
if cacheSize < totalSize {
|
|
|
p = p.Next
|
|
|
} else if cacheSize == totalSize {
|
|
|
var outPkt base.AvPacket
|
|
|
outPkt.PayloadType = unpacker.payloadType
|
|
|
outPkt.Timestamp = int64(p.Packet.Header.Timestamp / uint32(unpacker.clockRate/1000))
|
|
|
for _, a := range as {
|
|
|
outPkt.Payload = append(outPkt.Payload, a...)
|
|
|
}
|
|
|
unpacker.onAvPacket(outPkt)
|
|
|
|
|
|
list.Head.Next = p.Next
|
|
|
list.Size -= packetCount
|
|
|
return true, p.Packet.Header.Seq
|
|
|
} else {
|
|
|
Log.Errorf("cache size bigger then total size. cacheSize=%d, totalSize=%d",
|
|
|
cacheSize, totalSize)
|
|
|
return false, 0
|
|
|
}
|
|
|
}
|
|
|
// can reach here
|
|
|
}
|
|
|
|
|
|
// more complete access unit
|
|
|
for i := range aus {
|
|
|
var outPkt base.AvPacket
|
|
|
outPkt.PayloadType = unpacker.payloadType
|
|
|
outPkt.Timestamp = int64(p.Packet.Header.Timestamp / uint32(unpacker.clockRate/1000))
|
|
|
// TODO chef: 这里1024的含义
|
|
|
outPkt.Timestamp += int64(uint32(i * (1024 * 1000) / unpacker.clockRate))
|
|
|
outPkt.Payload = b[aus[i].pos : aus[i].pos+aus[i].size]
|
|
|
unpacker.onAvPacket(outPkt)
|
|
|
}
|
|
|
|
|
|
list.Head.Next = p.Next
|
|
|
list.Size--
|
|
|
return true, p.Packet.Header.Seq
|
|
|
}
|
|
|
|
|
|
type au struct {
|
|
|
size uint32 // 该音频帧的大小
|
|
|
pos uint32 // 相对rtp body的位置
|
|
|
}
|
|
|
|
|
|
func parseAu(b []byte) (ret []au) {
|
|
|
// TODO(chef): [fix] 解析b时,没有判断长度有效性 202207
|
|
|
|
|
|
// AU Header Section
|
|
|
var auHeadersLength uint32
|
|
|
auHeadersLength = uint32(b[0])<<8 + uint32(b[1])
|
|
|
auHeadersLength = (auHeadersLength + 7) / 8
|
|
|
|
|
|
// TODO chef: 这里的2是写死的,正常是外部传入auSize和auIndex所占位数的和
|
|
|
const auHeaderSize = 2
|
|
|
nbAuHeaders := uint32(auHeadersLength) / auHeaderSize // 有多少个AU-Header
|
|
|
|
|
|
pauh := uint32(2) // AU Header pos
|
|
|
pau := uint32(2) + auHeadersLength // AU pos
|
|
|
|
|
|
for i := uint32(0); i < nbAuHeaders; i++ {
|
|
|
// TODO chef: auSize和auIndex所在的位数是写死的13bit,3bit,标准的做法应该从外部传入,比如从sdp中获取后传入
|
|
|
auSize := uint32(b[pauh])<<8 | uint32(b[pauh+1]&0xF8) // 13bit
|
|
|
auSize /= 8
|
|
|
// 注意,fragment时,auIndex并不可靠。见TestAacCase1
|
|
|
//auIndex := b[pauh+1] & 0x7
|
|
|
//Log.Debugf("~ %d %d", auSize, auIndex)
|
|
|
|
|
|
ret = append(ret, au{
|
|
|
size: auSize,
|
|
|
pos: pau,
|
|
|
})
|
|
|
|
|
|
pauh += 2
|
|
|
pau += auSize
|
|
|
}
|
|
|
|
|
|
if (nbAuHeaders > 1 && pau != uint32(len(b))) ||
|
|
|
(nbAuHeaders == 1 && pau < uint32(len(b))) {
|
|
|
Log.Warnf("rtp packet size invalid. nbAuHeaders=%d, pau=%d, len(b)=%d, auHeadersLength=%d", nbAuHeaders, pau, len(b), auHeadersLength)
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|