rewrite handleH264Payload, support BuggyCameraHasAnnexbH264Packet

This commit is contained in:
nareix 2016-06-15 10:28:34 +08:00
parent e6b1c2561e
commit b0ccdad10b

261
client.go
View File

@ -531,16 +531,7 @@ func (self *Stream) makeCodecData() (err error) {
case av.H264: case av.H264:
for _, nalu := range media.SpropParameterSets { for _, nalu := range media.SpropParameterSets {
if len(nalu) > 0 { if len(nalu) > 0 {
switch nalu[0] & 0x1f { self.handleH264Payload(0, nalu)
case 7:
if len(self.sps) == 0 {
self.sps = nalu
}
case 8:
if len(self.pps) == 0 {
self.pps = nalu
}
}
} }
} }
@ -548,16 +539,7 @@ func (self *Stream) makeCodecData() (err error) {
if nalus, ok := h264parser.SplitNALUs(media.Config); ok { if nalus, ok := h264parser.SplitNALUs(media.Config); ok {
for _, nalu := range nalus { for _, nalu := range nalus {
if len(nalu) > 0 { if len(nalu) > 0 {
switch nalu[0] & 0x1f { self.handleH264Payload(0, nalu)
case 7:
if len(self.sps) == 0 {
self.sps = nalu
}
case 8:
if len(self.pps) == 0 {
self.pps = nalu
}
}
} }
} }
} }
@ -600,7 +582,30 @@ func (self *Stream) makeCodecData() (err error) {
return return
} }
func (self *Stream) handleH264Payload(naluType byte, timestamp uint32, packet []byte) (err error) { func (self *Stream) handleBuggyCameraHasAnnexbH264Packet(timestamp uint32, packet []byte) (isBuggy bool, err error) {
if len(packet) >= 4 && packet[0] == 0 && packet[1] == 0 && packet[2] == 0 && packet[3] == 1 {
isBuggy = true
if nalus, ok := h264parser.SplitNALUs(packet); ok {
for _, nalu := range nalus {
if len(nalu) > 0 {
if err = self.handleH264Payload(timestamp, nalu); err != nil {
return
}
}
}
}
}
return
}
func (self *Stream) handleH264Payload(timestamp uint32, packet []byte) (err error) {
var isBuggy bool
if isBuggy, err = self.handleBuggyCameraHasAnnexbH264Packet(timestamp, packet); isBuggy {
return
}
naluType := packet[0]&0x1f
/* /*
Table 7-1 NAL unit type codes Table 7-1 NAL unit type codes
1 Coded slice of a non-IDR picture 1 Coded slice of a non-IDR picture
@ -608,15 +613,39 @@ func (self *Stream) handleH264Payload(naluType byte, timestamp uint32, packet []
6 Supplemental enhancement information (SEI) 6 Supplemental enhancement information (SEI)
7 Sequence parameter set 7 Sequence parameter set
8 Picture parameter set 8 Picture parameter set
1-23 NAL unit Single NAL unit packet 5.6
24 STAP-A Single-time aggregation packet 5.7.1
25 STAP-B Single-time aggregation packet 5.7.1
26 MTAP16 Multi-time aggregation packet 5.7.2
27 MTAP24 Multi-time aggregation packet 5.7.2
28 FU-A Fragmentation unit 5.8
29 FU-B Fragmentation unit 5.8
30-31 reserved -
*/ */
switch naluType {
case 6: // SEI ignored
case 7: // sps switch {
default:
if naluType >= 1 && naluType <= 23 {
if naluType == 5 {
self.pkt.IsKeyFrame = true
}
self.gotpkt = true
self.pkt.Data = packet
self.timestamp = timestamp
} else {
err = fmt.Errorf("rtsp: unsupported H264 naluType=%d", naluType)
return
}
case naluType == 6: // SEI ignored
case naluType == 7: // sps
if self.client != nil && self.client.DebugRtp { if self.client != nil && self.client.DebugRtp {
fmt.Println("rtsp: got sps") fmt.Println("rtsp: got sps")
} }
if bytes.Compare(self.sps, packet) != 0 { if len(self.sps) == 0 {
self.sps = packet
} else if bytes.Compare(self.sps, packet) != 0 {
self.spsChanged = true self.spsChanged = true
self.sps = packet self.sps = packet
if self.client != nil && self.client.DebugRtp { if self.client != nil && self.client.DebugRtp {
@ -624,11 +653,13 @@ func (self *Stream) handleH264Payload(naluType byte, timestamp uint32, packet []
} }
} }
case 8: // pps case naluType == 8: // pps
if self.client != nil && self.client.DebugRtp { if self.client != nil && self.client.DebugRtp {
fmt.Println("rtsp: got pps") fmt.Println("rtsp: got pps")
} }
if bytes.Compare(self.pps, packet) != 0 { if len(self.pps) == 0 {
self.pps = packet
} else if bytes.Compare(self.pps, packet) != 0 {
self.ppsChanged = true self.ppsChanged = true
self.pps = packet self.pps = packet
if self.client != nil && self.client.DebugRtp { if self.client != nil && self.client.DebugRtp {
@ -636,13 +667,72 @@ func (self *Stream) handleH264Payload(naluType byte, timestamp uint32, packet []
} }
} }
default: case naluType == 28: // FU-A
if naluType == 5 { /*
self.pkt.IsKeyFrame = true 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator | FU header | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 14. RTP payload format for FU-A
The FU indicator octet has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
The FU header has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
S: 1 bit
When set to one, the Start bit indicates the start of a fragmented
NAL unit. When the following FU payload is not the start of a
fragmented NAL unit payload, the Start bit is set to zero.
E: 1 bit
When set to one, the End bit indicates the end of a fragmented NAL
unit, i.e., the last byte of the payload is also the last byte of
the fragmented NAL unit. When the following FU payload is not the
last fragment of a fragmented NAL unit, the End bit is set to
zero.
R: 1 bit
The Reserved bit MUST be equal to 0 and MUST be ignored by the
receiver.
Type: 5 bits
The NAL unit payload type as defined in table 7-1 of [1].
*/
fuIndicator := packet[0]
fuHeader := packet[1]
isStart := fuHeader&0x80 != 0
isEnd := fuHeader&0x40 != 0
if isStart {
self.fuBuffer = []byte{fuIndicator&0xe0 | fuHeader&0x1f}
} }
self.gotpkt = true self.fuBuffer = append(self.fuBuffer, packet[2:]...)
self.pkt.Data = packet if isEnd {
self.timestamp = timestamp if err = self.handleH264Payload(timestamp, self.fuBuffer); err != nil {
return
}
}
case naluType == 24:
err = fmt.Errorf("rtsp: unsupported H264 STAP-A")
return
} }
return return
@ -656,107 +746,10 @@ func (self *Stream) handlePacket(timestamp uint32, packet []byte) (err error) {
switch self.Type() { switch self.Type() {
case av.H264: case av.H264:
/* if self.client != nil && self.client.DebugRtp {
+---------------+ fmt.Printf("rtsp: h264 data=%x\n", packet)
|0|1|2|3|4|5|6|7| }
+-+-+-+-+-+-+-+-+ if err = self.handleH264Payload(timestamp, packet); err != nil {
|F|NRI| Type |
+---------------+
*/
naluType := packet[0] & 0x1f
/*
NAL Unit Packet Packet Type Name Section
Type Type
-------------------------------------------------------------
0 reserved -
1-23 NAL unit Single NAL unit packet 5.6
24 STAP-A Single-time aggregation packet 5.7.1
25 STAP-B Single-time aggregation packet 5.7.1
26 MTAP16 Multi-time aggregation packet 5.7.2
27 MTAP24 Multi-time aggregation packet 5.7.2
28 FU-A Fragmentation unit 5.8
29 FU-B Fragmentation unit 5.8
30-31 reserved -
*/
switch {
case naluType >= 1 && naluType <= 23:
if err = self.handleH264Payload(naluType, timestamp, packet); err != nil {
return
}
case naluType == 28: // FU-A
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator | FU header | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure 14. RTP payload format for FU-A
The FU indicator octet has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
The FU header has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+---------------+
S: 1 bit
When set to one, the Start bit indicates the start of a fragmented
NAL unit. When the following FU payload is not the start of a
fragmented NAL unit payload, the Start bit is set to zero.
E: 1 bit
When set to one, the End bit indicates the end of a fragmented NAL
unit, i.e., the last byte of the payload is also the last byte of
the fragmented NAL unit. When the following FU payload is not the
last fragment of a fragmented NAL unit, the End bit is set to
zero.
R: 1 bit
The Reserved bit MUST be equal to 0 and MUST be ignored by the
receiver.
Type: 5 bits
The NAL unit payload type as defined in table 7-1 of [1].
*/
fuIndicator := packet[0]
fuHeader := packet[1]
isStart := fuHeader&0x80 != 0
isEnd := fuHeader&0x40 != 0
naluType := fuHeader & 0x1f
if isStart {
self.fuBuffer = []byte{fuIndicator&0xe0 | fuHeader&0x1f}
}
self.fuBuffer = append(self.fuBuffer, packet[2:]...)
if isEnd {
if err = self.handleH264Payload(naluType, timestamp, self.fuBuffer); err != nil {
return
}
}
case naluType == 24:
err = fmt.Errorf("rtsp: unsupported H264 STAP-A")
return
default:
err = fmt.Errorf("rtsp: unsupported H264 naluType=%d", naluType)
return return
} }