From accb2092d50f3e100ed107fa05bc3400c8251415 Mon Sep 17 00:00:00 2001 From: q191201771 <191201771@qq.com> Date: Thu, 18 Aug 2022 22:06:07 +0800 Subject: [PATCH] =?UTF-8?q?[feat]=20rtp=20unpacker=E6=94=AF=E6=8C=81hevc?= =?UTF-8?q?=20ap=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/rtprtcp/rtp.go | 10 +++++++++- pkg/rtprtcp/rtp_packet.go | 3 ++- pkg/rtprtcp/rtp_unpacker_avc_hevc.go | 28 ++++++++++++++++++++-------- pkg/rtprtcp/rtp_unpacker_test.go | 28 ++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 10 deletions(-) diff --git a/pkg/rtprtcp/rtp.go b/pkg/rtprtcp/rtp.go index cfc5141..146bd78 100644 --- a/pkg/rtprtcp/rtp.go +++ b/pkg/rtprtcp/rtp.go @@ -8,6 +8,8 @@ package rtprtcp +// h264的格式: +// // rfc3984 5.2. Common Structure of the RTP Payload Format // Table 1. Summary of NAL unit types and their payload structures // @@ -22,13 +24,19 @@ package rtprtcp // 28 FU-A Fragmentation unit 5.8 // 29 FU-B Fragmentation unit 5.8 // 30-31 undefined - +// +// h265的格式: +// +// rfc7798 +// 4.4.2. Aggregation Packets (APs) +// 4.4.3. Fragmentation Units const ( NaluTypeAvcSingleMax = 23 NaluTypeAvcStapa = 24 // one packet, multiple nals NaluTypeAvcFua = 28 - // NaluTypeHevcFua TODO(chef): hevc有stapa格式吗 + NaluTypeHevcAp = 48 NaluTypeHevcFua = 49 ) diff --git a/pkg/rtprtcp/rtp_packet.go b/pkg/rtprtcp/rtp_packet.go index 5471862..1966bc1 100644 --- a/pkg/rtprtcp/rtp_packet.go +++ b/pkg/rtprtcp/rtp_packet.go @@ -43,7 +43,8 @@ const ( PositionTypeFuaStart uint8 = 2 PositionTypeFuaMiddle uint8 = 3 PositionTypeFuaEnd uint8 = 4 - PositionTypeStapa uint8 = 5 + PositionTypeStapa uint8 = 5 // 1个rtp包包含多个帧,目前供h264的stapa使用 + PositionTypeAp uint8 = 6 // 1个rtp包包含多个帧,目前供h265的ap使用 ) type RtpHeader struct { diff --git a/pkg/rtprtcp/rtp_unpacker_avc_hevc.go b/pkg/rtprtcp/rtp_unpacker_avc_hevc.go index 913d578..d4af5a8 100644 --- a/pkg/rtprtcp/rtp_unpacker_avc_hevc.go +++ b/pkg/rtprtcp/rtp_unpacker_avc_hevc.go @@ -9,10 +9,12 @@ package rtprtcp import ( + "encoding/hex" "github.com/q191201771/lal/pkg/avc" "github.com/q191201771/lal/pkg/base" "github.com/q191201771/lal/pkg/hevc" "github.com/q191201771/naza/pkg/bele" + "github.com/q191201771/naza/pkg/nazabytes" ) type RtpUnpackerAvcHevc struct { @@ -59,19 +61,26 @@ func (unpacker *RtpUnpackerAvcHevc) TryUnpackOne(list *RtpPacketList) (unpackedF unpacker.onAvPacket(pkt) return true, first.Packet.Header.Seq - case PositionTypeStapa: + case PositionTypeStapa, PositionTypeAp: + skip := uint32(1) + if first.Packet.positionType == PositionTypeStapa { + skip = 1 + } else if first.Packet.positionType == PositionTypeAp { + skip = 2 + } + var pkt base.AvPacket pkt.PayloadType = unpacker.payloadType pkt.Timestamp = int64(first.Packet.Header.Timestamp / uint32(unpacker.clockRate/1000)) - // 跳过首字节,并且将多nalu前的2字节长度,替换成4字节长度 - buf := first.Packet.Raw[first.Packet.Header.payloadOffset+1:] + // 跳过前面的字节,并且将多nalu前的2字节长度,替换成4字节长度 + buf := first.Packet.Raw[first.Packet.Header.payloadOffset+skip:] // 使用两次遍历,第一次遍历找出总大小,第二次逐个拷贝,目的是使得内存块一次就申请好,不用动态扩容造成额外性能开销 totalSize := 0 for i := 0; i != len(buf); { if len(buf)-i < 2 { - Log.Errorf("invalid STAP-A packet.") + Log.Errorf("invalid STAP-A packet. len(buf)=%d, i=%d", len(buf), i) return false, 0 } naluSize := int(bele.BeUint16(buf[i:])) @@ -261,7 +270,8 @@ func calcPositionIfNeededAvc(pkt *RtpPacket) { } else if outerNaluType == NaluTypeAvcStapa { pkt.positionType = PositionTypeStapa } else { - Log.Errorf("unknown nalu type. outerNaluType=%d", outerNaluType) + Log.Errorf("unknown nalu type. outerNaluType=%d(%d), header=%+v, len=%d, raw=%s", + b[0], outerNaluType, pkt.Header, len(pkt.Raw), hex.Dump(nazabytes.Prefix(pkt.Raw, 128))) } return @@ -323,9 +333,11 @@ func calcPositionIfNeededHevc(pkt *RtpPacket) { pkt.positionType = PositionTypeFuaMiddle return + } else if outerNaluType == NaluTypeHevcAp { + pkt.positionType = PositionTypeAp + return } - // TODO chef: 没有实现 AP 48 - Log.Errorf("unknown nalu type. outerNaluType=%d(%d), header=%+v, len=%d", - b[0], outerNaluType, pkt.Header, len(pkt.Raw)) + Log.Errorf("unknown nalu type. outerNaluType=%d(%d), header=%+v, len=%d, raw=%s", + b[0], outerNaluType, pkt.Header, len(pkt.Raw), hex.Dump(nazabytes.Prefix(pkt.Raw, 128))) } diff --git a/pkg/rtprtcp/rtp_unpacker_test.go b/pkg/rtprtcp/rtp_unpacker_test.go index 6fee801..490024d 100644 --- a/pkg/rtprtcp/rtp_unpacker_test.go +++ b/pkg/rtprtcp/rtp_unpacker_test.go @@ -83,6 +83,25 @@ func TestHevcCase1(t *testing.T) { }) } +func TestHevcCase2(t *testing.T) { + // vps40,sps42,pps44,sei4e + // 85 = 2 + 24 + 2 + 35 + 2 + 8 + 2 + 10 + ss := []string{ + "80601191bd9ee38884bc42f46001001840010c01ffff016000000300b0000003000003007bac09000023420101016000000300b0000003000003007ba003c08010e58dae4932f4dc040404020000084401c0f2f03c9000000a4e01e5040c7500008000", + } + out, _ := hex.DecodeString("0000001840010c01ffff016000000300b0000003000003007bac090000000023420101016000000300b0000003000003007ba003c08010e58dae4932f4dc0404040200000000084401c0f2f03c90000000000a4e01e5040c7500008000") + + testHelperTemplete(t, base.AvPacketPtHevc, 90000, 128, ss, func(rtpPackets []RtpPacket) []base.AvPacket { + return []base.AvPacket{ + { + Timestamp: 35347852, + PayloadType: base.AvPacketPtHevc, + Payload: out, + }, + } + }) +} + func TestAacCase1(t *testing.T) { ss := []string{ "80e10e9a56843e4cf0bdf2fe00102d10214e6c425f74815f92415f94415f924100000114008a004027f313d564a770026fd01203c9cbac420e1aecaa41efb4619391309daa7938b4b905989c5c293c024819e4234eb324934327e3f083c98c2220137bc9b5b2bae5809351710e4bfec0dec11fffe0ab6e568f8357fb74c3461e892fc3a4e22ac512fa73bdc13004b9d73e21c5221387922692939994e38ab1516ea2cfb64df8cffb5468a81e4704f255a5139f7f21d622b944e0b08221916d4ba6e10a31b2a148c38642d1c8b2b12a15681c0f0b589160feb32b43c7ebade413590916a934148ca7915d6250904e5172a3ecc612ab23fd4431b0eef591be52155e4a0ac8564108012689c4df89221892e50d8fca64a747bb2313908211004222ea6a848132e87935978e03845905ccc057c743c7424e64e2338bfe52090d4a5a961f35ec5e14befbc2b3d41f89bdfe949fc2dd40e141b13e397f84f7e1ef43f303df77407bdacc01c2832c3d3df65fe3bfde0001f37f85f4a021f27baf11e4f388fd5ce464337648fc89e6043a0c8268a44f0e024e112910c8b9bc282ee2e5587762b2752c08a422ac99558f904273f858d9de9938ef2502493ae3217c247410eb39395f084a117f6486161103c5cab0881d7c24ffd7123cdcac226bc292c2dc213d04f0b26dd864e6e149c3a4468a48d86124209e172166c5b331e434c8cae4276e191acc2682d692a51210c1ce2254102e048435919442449f2c57bb271364fbb67f1d79364ee004a28c88e75dd53210eef613186531f22908a5253a87e66423fe1bffef7dd95fed588acf815908808fefff2ffef581fe23b2b8e9fdfbd7e3f7071c05d40ec89401efbdf87beee9a9c1eff2d054c0f7ff5febc514514514514514514517d7fe0faf145145111fc0dd8218d9f9d064ee8895cb84ee848064e7593530495f87ffa276e76549a4e6c0e381270c24ea288e0e1d8ad270f0dc243210e413a84b160e085b10a416be12011022b31354b202020771fe376bf6afe387e67fe0fee8087bee102bf415fa0afd0400000e3e3e3fe001f8f8ff53eff60fafab04fe0877121cebad11c16048271174dc251cbdd3da84e0c9ba23dd312b26500020154a269d9c4520270444131665313103f0f7412d40de5c59cfff0f6383440fc588e986f10b35ddbfdb6be780f30eb25f49fd7e479062097adbc044ba3e0c956ef043c31d188a23d453e83ca71ca44df64805f4514916e71c7e760674293094980642012d104ba2cacd260456e2e93a8c1f492739f9dd445aba9241088de157cb3d976e20888a41b34808f3a4ca181528c989641e0a187dc5443494c896e4421711580a84276a12a229662108289464d105b1513f80841836f009c987f86969641eea943c86c475685fb09043ae947ac5d22ff6ff7c1d380a48885c2a7d03905668ec9fd1fcdf7fc700450094d16f034c90003df9240b851764658e101efb8ea83855071d6871c5126a8385556aa0db094e571d9dc7271352b846810c4e24000000000000038e60384c4f09800000021e17eb447ca381218ff036078221ec1e7843a466acc013c0130585c7518330993235855b71158610843210aa9ba05c22ea5984de5e1227e3e4d2dd942a1659f5320232b45bb6c6418df87b313c727fc3f1d170a6ecb0b74e4449209804a3bf270c98518182b79dd74412c24f7e4f45131a889442502df3928282006d0f165c6e4d39059e7404eb1092044c67267817686dc7dbe82281f1d2f65ddaf70e67250c77adbe39d09be32b8f0007d2f905140d3c34fb6784075ce77075dfb069da091017344c80b6b9a36ff1d93c22889d5a7ccaa2073ccf278e1f8e9c38e1c9a8f502b8e9c84938542ae3a7e1313c26240000000000000384c4f1cc4f09890000021f49fc3847d1b76e8613938122e759d2494b9e4634fc812ab747e3132beb075bf23fed67a0943a245082648a4d06e11166a25f110a24c0c993964042ff0a8d24e4108c489514499641221f84c013c06008e0301c2e0038e6009e0327c7326000001c", @@ -156,6 +175,13 @@ func TestAacCase2(t *testing.T) { }) } +// testHelperTemplete +// +// @param hexRtpPackets: rtp包的二进制数组 +// @param expectedFn: +// []RtpPacket: `hexRtpPackets`解析成的rtp包数组 +// []base.AvPacket: rtp包数组解析成的AvPacket数组 +// func testHelperTemplete(t *testing.T, payloadType base.AvPacketPt, clockRate int, maxSize int, hexRtpPackets []string, expectedFn func([]RtpPacket) []base.AvPacket) { rtpPackets, err := testHelperHexstream2rtppackets(hexRtpPackets) assert.Equal(t, nil, err) @@ -171,6 +197,8 @@ func testHelperAddPrefixLength(in []byte) (out []byte) { return } +// --------------------------------------------------------------------------------------------------------------------- + func testHelperUnpack(payloadType base.AvPacketPt, clockRate int, maxSize int, rtpPackets []RtpPacket) []base.AvPacket { var outPkts []base.AvPacket unpacker := DefaultRtpUnpackerFactory(payloadType, clockRate, maxSize, func(pkt base.AvPacket) {