Skip to content

Commit

Permalink
Merge pull request #141 from joestarzxh/master
Browse files Browse the repository at this point in the history
[fix] rtsp pub和rtmp pub: 解析H265流中的类型字段不够全面,导致推流失败 #140
  • Loading branch information
q191201771 authored Apr 7, 2022
2 parents 66b3baf + 4040450 commit cae8ebe
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 84 deletions.
59 changes: 44 additions & 15 deletions pkg/hevc/hevc.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,60 @@ var (
var NaluTypeMapping = map[uint8]string{
NaluTypeSliceTrailN: "TrailN",
NaluTypeSliceTrailR: "TrailR",
NaluTypeSliceIdr: "IDR",
NaluTypeSliceIdrNlp: "IDRNLP",
NaluTypeSliceCranut: "CRANUT",
NaluTypeVps: "VPS",
NaluTypeSps: "SPS",
NaluTypePps: "PPS",
NaluTypeAud: "AUD",
NaluTypeSei: "SEI",
NaluTypeSeiSuffix: "SEISuffix",

NaluTypeSliceTsaN: "TsaN",
NaluTypeSliceTsaR: "TsaR",
NaluTypeSliceStsaN: "StsaN",
NaluTypeSliceStsaR: "StsaR",
NaluTypeSliceRadlN: "RadlN",
NaluTypeSliceRadlR: "RadlR",
NaluTypeSliceRaslN: "RaslN",
NaluTypeSliceRaslR: "RaslR",

NaluTypeSliceBlaWlp: "BlaWlp",
NaluTypeSliceBlaWradl: "BlaWradl",
NaluTypeSliceBlaNlp: "BlaNlp",
NaluTypeSliceIdr: "IDR",
NaluTypeSliceIdrNlp: "IDRNLP",
NaluTypeSliceCranut: "CRANUT",
NaluTypeSliceRsvIrapVcl22: "IDR",
NaluTypeSliceRsvIrapVcl23: "IDR",

NaluTypeVps: "VPS",
NaluTypeSps: "SPS",
NaluTypePps: "PPS",
NaluTypeAud: "AUD",
NaluTypeSei: "SEI",
NaluTypeSeiSuffix: "SEISuffix",
}

// ISO_IEC_23008-2_2013.pdf
// Table 7-1 – NAL unit type codes and NAL unit type classes
const (
NaluTypeSliceTrailN uint8 = 0 // 0x0
NaluTypeSliceTrailR uint8 = 1 // 0x01
NaluTypeSliceTsaN uint8 = 2 // 0x02
NaluTypeSliceTsaR uint8 = 3 // 0x03
NaluTypeSliceStsaN uint8 = 4 // 0x04
NaluTypeSliceStsaR uint8 = 5 // 0x05
NaluTypeSliceRadlN uint8 = 6 // 0x06
NaluTypeSliceRadlR uint8 = 7 // 0x07
NaluTypeSliceRaslN uint8 = 8 // 0x06
NaluTypeSliceRaslR uint8 = 9 // 0x09

// NaluTypeSliceIdr ...
//
// 19, 20, 21都是关键帧
// TODO(chef): 16,17,18也是关键帧吗?
//
NaluTypeSliceIdr uint8 = 19 // 0x13
NaluTypeSliceIdrNlp uint8 = 20 // 0x14
NaluTypeSliceCranut uint8 = 21 // 0x15
NaluTypeSliceBlaWlp uint8 = 16 // 0x10
NaluTypeSliceBlaWradl uint8 = 17 // 0x11
NaluTypeSliceBlaNlp uint8 = 18 // 0x12
NaluTypeSliceIdr uint8 = 19 // 0x13
NaluTypeSliceIdrNlp uint8 = 20 // 0x14
NaluTypeSliceCranut uint8 = 21 // 0x15
NaluTypeSliceRsvIrapVcl22 uint8 = 22 // 0x16
NaluTypeSliceRsvIrapVcl23 uint8 = 23 // 0x17

NaluTypeVps uint8 = 32 // 0x20
NaluTypeSps uint8 = 33 // 0x21
Expand Down Expand Up @@ -185,7 +214,7 @@ func ParseVpsSpsPpsFromSeqHeaderWithoutMalloc(payload []byte) (vps, sps, pps []b
}
index++

if payload[index] != NaluTypeVps&0x3f {
if payload[index]&0x3f != NaluTypeVps {
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if numNalus := int(bele.BeUint16(payload[index+1:])); numNalus != 1 {
Expand All @@ -203,7 +232,7 @@ func ParseVpsSpsPpsFromSeqHeaderWithoutMalloc(payload []byte) (vps, sps, pps []b
if len(payload) < 38+vpsLen {
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if payload[index] != NaluTypeSps&0x3f {
if payload[index]&0x3f != NaluTypeSps {
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if numNalus := int(bele.BeUint16(payload[index+1:])); numNalus != 1 {
Expand All @@ -219,7 +248,7 @@ func ParseVpsSpsPpsFromSeqHeaderWithoutMalloc(payload []byte) (vps, sps, pps []b
if len(payload) < 43+vpsLen+spsLen {
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if payload[index] != NaluTypePps&0x3f {
if payload[index]&0x3f != NaluTypePps {
return nil, nil, nil, nazaerrors.Wrap(base.ErrHevc)
}
if numNalus := int(bele.BeUint16(payload[index+1:])); numNalus != 1 {
Expand Down
2 changes: 1 addition & 1 deletion pkg/remux/avpacket2rtmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ func (r *AvPacket2RtmpRemuxer) FeedAvPacket(pkt base.AvPacket) {
r.clearVideoSeqHeader()
}
} else {
if t == hevc.NaluTypeSliceIdr || t == hevc.NaluTypeSliceIdrNlp || t == hevc.NaluTypeSliceCranut {
if t >= hevc.NaluTypeSliceBlaWlp && t <= hevc.NaluTypeSliceRsvIrapVcl23 {
payload[0] = base.RtmpHevcKeyFrame
} else {
payload[0] = base.RtmpHevcInterFrame
Expand Down
4 changes: 3 additions & 1 deletion pkg/remux/rtmp2mpegts.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,9 @@ func (s *Rtmp2MpegtsRemuxer) feedVideo(msg base.RtmpMsg) {
}
} else {
switch nalType {
case hevc.NaluTypeSliceIdr, hevc.NaluTypeSliceIdrNlp, hevc.NaluTypeSliceCranut:
case hevc.NaluTypeSliceBlaWlp, hevc.NaluTypeSliceBlaWradl, hevc.NaluTypeSliceBlaNlp,
hevc.NaluTypeSliceIdr, hevc.NaluTypeSliceIdrNlp, hevc.NaluTypeSliceCranut,
hevc.NaluTypeSliceRsvIrapVcl22, hevc.NaluTypeSliceRsvIrapVcl23:
if !spsppsSent {
if s.videoOut, err = s.appendSpsPps(s.videoOut); err != nil {
Log.Warnf("[%s] append spspps by not exist.", s.UniqueKey)
Expand Down
17 changes: 11 additions & 6 deletions pkg/rtprtcp/rtp_packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,17 @@ func IsAvcBoundary(pkt RtpPacket) bool {

func IsHevcBoundary(pkt RtpPacket) bool {
boundaryNaluTypes := map[uint8]struct{}{
hevc.NaluTypeVps: {},
hevc.NaluTypeSps: {},
hevc.NaluTypePps: {},
hevc.NaluTypeSliceIdr: {},
hevc.NaluTypeSliceIdrNlp: {},
hevc.NaluTypeSliceCranut: {},
hevc.NaluTypeVps: {},
hevc.NaluTypeSps: {},
hevc.NaluTypePps: {},
hevc.NaluTypeSliceBlaWlp: {},
hevc.NaluTypeSliceBlaWradl: {},
hevc.NaluTypeSliceBlaNlp: {},
hevc.NaluTypeSliceIdr: {},
hevc.NaluTypeSliceIdrNlp: {},
hevc.NaluTypeSliceCranut: {},
hevc.NaluTypeSliceRsvIrapVcl22: {},
hevc.NaluTypeSliceRsvIrapVcl23: {},
}

b := pkt.Body()
Expand Down
104 changes: 43 additions & 61 deletions pkg/rtprtcp/rtp_unpacker_avc_hevc.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,72 +277,54 @@ func calcPositionIfNeededHevc(pkt *RtpPacket) {
// +-------------+-----------------+

outerNaluType := hevc.ParseNaluType(b[0])

switch outerNaluType {
case hevc.NaluTypeVps:
fallthrough
case hevc.NaluTypeSps:
fallthrough
case hevc.NaluTypePps:
fallthrough
case hevc.NaluTypeSei:
fallthrough
case hevc.NaluTypeSliceTrailN:
fallthrough
case hevc.NaluTypeSliceTrailR:
fallthrough
case hevc.NaluTypeSliceIdr:
fallthrough
case hevc.NaluTypeSliceIdrNlp:
fallthrough
case hevc.NaluTypeSliceCranut:
if _, ok := hevc.NaluTypeMapping[outerNaluType]; ok {
pkt.positionType = PositionTypeSingle
return
case NaluTypeHevcFua:
// Figure 1: The Structure of the HEVC NAL Unit Header

// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | PayloadHdr (Type=49) | FU header | DONL (cond) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
// | DONL (cond) | |
// |-+-+-+-+-+-+-+-+ |
// | FU payload |
// | |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | :...OPTIONAL RTP padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

// Figure 9: The Structure of an FU

// +---------------+
// |0|1|2|3|4|5|6|7|
// +-+-+-+-+-+-+-+-+
// |S|E| FuType |
// +---------------+

// Figure 10: The Structure of FU Header

startCode := (b[2] & 0x80) != 0
endCode := (b[2] & 0x40) != 0
} else {
if outerNaluType == NaluTypeHevcFua {
// Figure 1: The Structure of the HEVC NAL Unit Header

// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | PayloadHdr (Type=49) | FU header | DONL (cond) |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
// | DONL (cond) | |
// |-+-+-+-+-+-+-+-+ |
// | FU payload |
// | |
// | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | :...OPTIONAL RTP padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

// Figure 9: The Structure of an FU

// +---------------+
// |0|1|2|3|4|5|6|7|
// +-+-+-+-+-+-+-+-+
// |S|E| FuType |
// +---------------+

// Figure 10: The Structure of FU Header

startCode := (b[2] & 0x80) != 0
endCode := (b[2] & 0x40) != 0

if startCode {
pkt.positionType = PositionTypeFuaStart
return
}

if startCode {
pkt.positionType = PositionTypeFuaStart
return
}
if endCode {
pkt.positionType = PositionTypeFuaEnd
return
}

if endCode {
pkt.positionType = PositionTypeFuaEnd
pkt.positionType = PositionTypeFuaMiddle
return
} else {
Log.Errorf("unknown nalu type. outerNaluType=%d(%d), header=%+v, len=%d",
b[0], outerNaluType, pkt.Header, len(pkt.Raw))
}

pkt.positionType = PositionTypeFuaMiddle
return
default:
// TODO chef: 没有实现 AP 48
Log.Errorf("unknown nalu type. outerNaluType=%d(%d), header=%+v, len=%d",
b[0], outerNaluType, pkt.Header, len(pkt.Raw))
}

}

0 comments on commit cae8ebe

Please sign in to comment.