mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 23:26:54 +08:00
rtph264: accept non-compliant single FU-A frames (#649)
Some IP cameras (e.g. CostarHD) have been observed to emit single fragment RTP FU-A packets, with start and end bit both set, for sufficiently small H.264 P-frames. Rather than emit an error, workaround such non-compliant frames.
This commit is contained in:
@@ -90,10 +90,6 @@ func (d *Decoder) decodeNALUs(pkt *rtp.Packet) ([][]byte, error) {
|
||||
if start == 1 {
|
||||
d.resetFragments()
|
||||
|
||||
if end != 0 {
|
||||
return nil, fmt.Errorf("invalid FU-A packet (can't contain both a start and end bit)")
|
||||
}
|
||||
|
||||
nri := (pkt.Payload[0] >> 5) & 0x03
|
||||
typ := pkt.Payload[1] & 0x1F
|
||||
d.fragmentsSize = len(pkt.Payload[1:])
|
||||
@@ -101,6 +97,20 @@ func (d *Decoder) decodeNALUs(pkt *rtp.Packet) ([][]byte, error) {
|
||||
d.fragmentNextSeqNum = pkt.SequenceNumber + 1
|
||||
d.firstPacketReceived = true
|
||||
|
||||
// RFC 6184 clearly states:
|
||||
//
|
||||
// A fragmented NAL unit MUST NOT be transmitted in one FU; that is, the
|
||||
// Start bit and End bit MUST NOT both be set to one in the same FU
|
||||
// header.
|
||||
//
|
||||
// However, some vendors camera (e.g. CostarHD) have been observed to nevertheless
|
||||
// emit one fragmented NAL unit for sufficiently small P-frames.
|
||||
if end != 0 {
|
||||
nalus = [][]byte{joinFragments(d.fragments, d.fragmentsSize)}
|
||||
d.resetFragments()
|
||||
break
|
||||
}
|
||||
|
||||
return nil, ErrMorePacketsNeeded
|
||||
}
|
||||
|
||||
|
@@ -79,6 +79,38 @@ func TestDecodeCorruptedFragment(t *testing.T) {
|
||||
require.Equal(t, [][]byte{{0x01, 0x00}}, nalus)
|
||||
}
|
||||
|
||||
func TestDecodeNoncompliantFragment(t *testing.T) {
|
||||
d := &Decoder{}
|
||||
err := d.Init()
|
||||
require.NoError(t, err)
|
||||
|
||||
nalus, err := d.Decode(&rtp.Packet{
|
||||
Header: rtp.Header{
|
||||
Version: 2,
|
||||
Marker: true,
|
||||
PayloadType: 96,
|
||||
SequenceNumber: 18853,
|
||||
Timestamp: 1731630255,
|
||||
SSRC: 0x466b0000,
|
||||
},
|
||||
|
||||
// FU-A with both start and end bit intentionally set
|
||||
// While not compliant with RFC 6184, IP cameras from some vendors
|
||||
// (e.g. CostarHD) have been observed to produce such FU-A payloads for
|
||||
// sufficiently small P-frames.
|
||||
Payload: mergeBytes(
|
||||
[]byte{
|
||||
0x3c, // FU indicator
|
||||
0xc1, // FU header (start and end bit both intentionally set)
|
||||
0xe7, 0x00, // DON
|
||||
0xca, 0xfe, // Payload
|
||||
},
|
||||
),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, [][]byte{{0x21, 0xe7, 0x00, 0xca, 0xfe}}, nalus)
|
||||
}
|
||||
|
||||
func TestDecodeSTAPAWithPadding(t *testing.T) {
|
||||
d := &Decoder{}
|
||||
err := d.Init()
|
||||
|
Reference in New Issue
Block a user