You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lal/pkg/rtprtcp/rtp_unpacker_aac.go

215 lines
6.2 KiB
Go

// 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也会包含auau的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所在的位数是写死的13bit3bit标准的做法应该从外部传入比如从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
}