mirror of
https://github.com/aler9/gortsplib
synced 2025-10-06 07:37:07 +08:00
135 lines
2.8 KiB
Go
135 lines
2.8 KiB
Go
package rtpproc
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/pion/rtp"
|
|
|
|
"github.com/aler9/gortsplib/pkg/h264"
|
|
"github.com/aler9/gortsplib/pkg/rtph264"
|
|
)
|
|
|
|
const (
|
|
// 1500 (UDP MTU) - 20 (IP header) - 8 (UDP header)
|
|
maxPacketSize = 1472
|
|
)
|
|
|
|
// ProcessorOutput is the output of Process().
|
|
type ProcessorOutput struct {
|
|
Packet *rtp.Packet
|
|
PTSEqualsDTS bool
|
|
H264NALUs [][]byte
|
|
H264PTS time.Duration
|
|
}
|
|
|
|
// Processor is used to process incoming RTP packets, in order to:
|
|
// - remove padding
|
|
// - decode packets encoded with supported codecs
|
|
// - re-encode packets if they are bigger than maximum allowed.
|
|
type Processor struct {
|
|
isH264 bool
|
|
isTCP bool
|
|
|
|
h264Decoder *rtph264.Decoder
|
|
h264Encoder *rtph264.Encoder
|
|
}
|
|
|
|
// NewProcessor allocates a Processor.
|
|
func NewProcessor(isH264 bool, isTCP bool) *Processor {
|
|
p := &Processor{
|
|
isH264: isH264,
|
|
isTCP: isTCP,
|
|
}
|
|
|
|
if isH264 {
|
|
p.h264Decoder = &rtph264.Decoder{}
|
|
p.h264Decoder.Init()
|
|
}
|
|
|
|
return p
|
|
}
|
|
|
|
func (p *Processor) processH264(pkt *rtp.Packet) ([]*ProcessorOutput, error) {
|
|
// decode
|
|
nalus, pts, err := p.h264Decoder.DecodeUntilMarker(pkt)
|
|
if err != nil {
|
|
if err == rtph264.ErrNonStartingPacketAndNoPrevious ||
|
|
err == rtph264.ErrMorePacketsNeeded {
|
|
return []*ProcessorOutput{{
|
|
Packet: pkt,
|
|
PTSEqualsDTS: false,
|
|
}}, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
ptsEqualsDTS := h264.IDRPresent(nalus)
|
|
|
|
// re-encode if packets use non-standard sizes
|
|
if p.isTCP && p.h264Encoder == nil && pkt.MarshalSize() > maxPacketSize {
|
|
v1 := pkt.SSRC
|
|
v2 := pkt.SequenceNumber
|
|
v3 := pkt.Timestamp
|
|
p.h264Encoder = &rtph264.Encoder{
|
|
PayloadType: pkt.PayloadType,
|
|
SSRC: &v1,
|
|
InitialSequenceNumber: &v2,
|
|
InitialTimestamp: &v3,
|
|
}
|
|
p.h264Encoder.Init()
|
|
}
|
|
|
|
if p.h264Encoder != nil {
|
|
packets, err := p.h264Encoder.Encode(nalus, pts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
output := make([]*ProcessorOutput, len(packets))
|
|
|
|
for i, pkt := range packets {
|
|
if i != len(packets)-1 {
|
|
output[i] = &ProcessorOutput{
|
|
Packet: pkt,
|
|
PTSEqualsDTS: false,
|
|
}
|
|
} else {
|
|
output[i] = &ProcessorOutput{
|
|
Packet: pkt,
|
|
PTSEqualsDTS: ptsEqualsDTS,
|
|
}
|
|
}
|
|
}
|
|
|
|
return output, nil
|
|
}
|
|
|
|
return []*ProcessorOutput{{
|
|
Packet: pkt,
|
|
PTSEqualsDTS: ptsEqualsDTS,
|
|
H264NALUs: nalus,
|
|
H264PTS: pts,
|
|
}}, nil
|
|
}
|
|
|
|
// Process processes a RTP packet.
|
|
func (p *Processor) Process(pkt *rtp.Packet) ([]*ProcessorOutput, error) {
|
|
// remove padding
|
|
pkt.Header.Padding = false
|
|
pkt.PaddingSize = 0
|
|
|
|
if p.h264Decoder != nil {
|
|
return p.processH264(pkt)
|
|
}
|
|
|
|
if p.isTCP && pkt.MarshalSize() > maxPacketSize {
|
|
return nil, fmt.Errorf("payload size (%d) greater than maximum allowed (%d)",
|
|
pkt.MarshalSize(), maxPacketSize)
|
|
}
|
|
|
|
return []*ProcessorOutput{{
|
|
Packet: pkt,
|
|
PTSEqualsDTS: true,
|
|
}}, nil
|
|
}
|