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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// 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
}