rtph264: support streams that encode NALUs into Annex-B

(https://github.com/aler9/rtsp-simple-server/issues/1029)
This commit is contained in:
aler9
2022-07-24 01:07:25 +02:00
parent a301701169
commit 73830e29be
2 changed files with 95 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
package rtph264
import (
"bytes"
"errors"
"fmt"
"time"
@@ -28,6 +29,8 @@ type Decoder struct {
fragmentedMode bool
fragmentedParts [][]byte
fragmentedSize int
firstNALUParsed bool
annexBMode bool
// for DecodeUntilMarker()
naluBuffer [][]byte
@@ -46,6 +49,7 @@ func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
}
typ := naluType(pkt.Payload[0] & 0x1F)
switch typ {
case naluTypeSTAPA:
var nalus [][]byte
@@ -77,6 +81,13 @@ func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
}
d.firstPacketReceived = true
var err error
nalus, err = d.finalize(nalus)
if err != nil {
return nil, 0, err
}
return nalus, d.timeDecoder.Decode(pkt.Timestamp), nil
case naluTypeFUA: // first packet of a fragmented NALU
@@ -112,8 +123,17 @@ func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
return nil, 0, fmt.Errorf("packet type not supported (%v)", typ)
}
nalus := [][]byte{pkt.Payload}
d.firstPacketReceived = true
return [][]byte{pkt.Payload}, d.timeDecoder.Decode(pkt.Timestamp), nil
var err error
nalus, err = d.finalize(nalus)
if err != nil {
return nil, 0, err
}
return nalus, d.timeDecoder.Decode(pkt.Timestamp), nil
}
// we are decoding a fragmented NALU
@@ -157,10 +177,18 @@ func (d *Decoder) Decode(pkt *rtp.Packet) ([][]byte, time.Duration, error) {
for _, p := range d.fragmentedParts {
n += copy(ret[n:], p)
}
nalus := [][]byte{ret}
d.fragmentedParts = d.fragmentedParts[:0]
d.fragmentedMode = false
return [][]byte{ret}, d.timeDecoder.Decode(pkt.Timestamp), nil
var err error
nalus, err = d.finalize(nalus)
if err != nil {
return nil, 0, err
}
return nalus, d.timeDecoder.Decode(pkt.Timestamp), nil
}
// DecodeUntilMarker decodes NALUs from a RTP/H264 packet and puts them in a buffer.
@@ -188,3 +216,39 @@ func (d *Decoder) DecodeUntilMarker(pkt *rtp.Packet) ([][]byte, time.Duration, e
return ret, pts, nil
}
func (d *Decoder) finalize(nalus [][]byte) ([][]byte, error) {
// some cameras / servers wrap NALUs into Annex-B
if !d.firstNALUParsed {
d.firstNALUParsed = true
if len(nalus) == 1 {
nalu := nalus[0]
i := bytes.Index(nalu, []byte{0x00, 0x00, 0x00, 0x01})
if i >= 0 {
d.annexBMode = true
if !bytes.HasPrefix(nalu, []byte{0x00, 0x00, 0x00, 0x01}) {
nalu = append([]byte{0x00, 0x00, 0x00, 0x01}, nalu...)
}
return h264.AnnexBUnmarshal(nalu)
}
}
} else if d.annexBMode {
if len(nalus) != 1 {
return nil, fmt.Errorf("multiple NALUs in Annex-B mode are not supported")
}
nalu := nalus[0]
if !bytes.HasPrefix(nalu, []byte{0x00, 0x00, 0x00, 0x01}) {
nalu = append([]byte{0x00, 0x00, 0x00, 0x01}, nalu...)
}
return h264.AnnexBUnmarshal(nalu)
}
return nalus, nil
}

View File

@@ -418,6 +418,35 @@ func TestDecodeSTAPAWithPadding(t *testing.T) {
}, nalus)
}
func TestDecodeAnnexB(t *testing.T) {
d := &Decoder{}
d.Init()
for i := 0; i < 2; i++ {
nalus, _, err := d.Decode(&rtp.Packet{
Header: rtp.Header{
Version: 2,
Marker: true,
PayloadType: 96,
SequenceNumber: 17647,
Timestamp: 2289531307,
SSRC: 0x9dbb7812,
},
Payload: mergeBytes(
[]byte{0x00, 0x00, 0x00, 0x01},
[]byte{0x01, 0x02, 0x03, 0x04},
[]byte{0x00, 0x00, 0x00, 0x01},
[]byte{0x01, 0x02, 0x03, 0x04},
),
})
require.NoError(t, err)
require.Equal(t, [][]byte{
{0x01, 0x02, 0x03, 0x04},
{0x01, 0x02, 0x03, 0x04},
}, nalus)
}
}
func TestDecodeErrors(t *testing.T) {
for _, ca := range []struct {
name string