diff --git a/codecs/common.go b/codecs/common.go index 5da8aaf..e807a0a 100644 --- a/codecs/common.go +++ b/codecs/common.go @@ -22,8 +22,18 @@ func (d *audioDepacketizer) IsPartitionHead(_ []byte) bool { } // videoDepacketizer is a mixin for video codec depacketizers -type videoDepacketizer struct{} +type videoDepacketizer struct { + zeroAllocation bool +} func (d *videoDepacketizer) IsPartitionTail(marker bool, _ []byte) bool { return marker } + +// SetZeroAllocation enables Zero Allocation mode for the depacketizer +// By default the Depacketizers will allocate as they parse. These allocations +// are needed for Metadata and other optional values. If you don't need this information +// enabling SetZeroAllocation gives you higher performance at a reduced feature set. +func (d *videoDepacketizer) SetZeroAllocation(zeroAllocation bool) { + d.zeroAllocation = zeroAllocation +} diff --git a/codecs/h264_packet.go b/codecs/h264_packet.go index 583e189..3021fc0 100644 --- a/codecs/h264_packet.go +++ b/codecs/h264_packet.go @@ -188,14 +188,16 @@ type H264Packet struct { videoDepacketizer } -func (p *H264Packet) doPackaging(nalu []byte) []byte { +func (p *H264Packet) doPackaging(buf, nalu []byte) []byte { if p.IsAVC { - naluLength := make([]byte, 4) - binary.BigEndian.PutUint32(naluLength, uint32(len(nalu))) - return append(naluLength, nalu...) + buf = binary.BigEndian.AppendUint32(buf, uint32(len(nalu))) + buf = append(buf, nalu...) + return buf } - return append(annexbNALUStartCode, nalu...) + buf = append(buf, annexbNALUStartCode...) + buf = append(buf, nalu...) + return buf } // IsDetectedFinalPacketInSequence returns true of the packet passed in has the @@ -206,6 +208,14 @@ func (p *H264Packet) IsDetectedFinalPacketInSequence(rtpPacketMarketBit bool) bo // Unmarshal parses the passed byte slice and stores the result in the H264Packet this method is called upon func (p *H264Packet) Unmarshal(payload []byte) ([]byte, error) { + if p.zeroAllocation { + return payload, nil + } + + return p.parseBody(payload) +} + +func (p *H264Packet) parseBody(payload []byte) ([]byte, error) { if len(payload) == 0 { return nil, fmt.Errorf("%w: %d <=0", errShortPacket, len(payload)) } @@ -215,7 +225,7 @@ func (p *H264Packet) Unmarshal(payload []byte) ([]byte, error) { naluType := payload[0] & naluTypeBitmask switch { case naluType > 0 && naluType < 24: - return p.doPackaging(payload), nil + return p.doPackaging(nil, payload), nil case naluType == stapaNALUType: currOffset := int(stapaHeaderSize) @@ -228,7 +238,7 @@ func (p *H264Packet) Unmarshal(payload []byte) ([]byte, error) { return nil, fmt.Errorf("%w STAP-A declared size(%d) is larger than buffer(%d)", errShortPacket, naluSize, len(payload)-currOffset) } - result = append(result, p.doPackaging(payload[currOffset:currOffset+naluSize])...) + result = p.doPackaging(result, payload[currOffset:currOffset+naluSize]) currOffset += naluSize } return result, nil @@ -251,7 +261,7 @@ func (p *H264Packet) Unmarshal(payload []byte) ([]byte, error) { nalu := append([]byte{}, naluRefIdc|fragmentedNaluType) nalu = append(nalu, p.fuaBuffer...) p.fuaBuffer = nil - return p.doPackaging(nalu), nil + return p.doPackaging(nil, nalu), nil } return []byte{}, nil diff --git a/depacketizer.go b/depacketizer.go index 0439a53..d10ad89 100644 --- a/depacketizer.go +++ b/depacketizer.go @@ -5,11 +5,15 @@ package rtp // Depacketizer depacketizes a RTP payload, removing any RTP specific data from the payload type Depacketizer interface { + // Unmarshal parses the RTP payload and returns media. + // Metadata may be stored on the Depacketizer itself Unmarshal(packet []byte) ([]byte, error) + // Checks if the packet is at the beginning of a partition. This // should return false if the result could not be determined, in // which case the caller will detect timestamp discontinuities. IsPartitionHead(payload []byte) bool + // Checks if the packet is at the end of a partition. This should // return false if the result could not be determined. IsPartitionTail(marker bool, payload []byte) bool