Files
gortsplib/pkg/formats/rtpmpeg4audiolatm/decoder.go
2023-08-05 14:18:04 +02:00

96 lines
2.3 KiB
Go

package rtpmpeg4audiolatm
import (
"errors"
"fmt"
"time"
"github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio"
"github.com/pion/rtp"
"github.com/bluenviron/gortsplib/v3/pkg/rtptime"
)
// ErrMorePacketsNeeded is returned when more packets are needed.
var ErrMorePacketsNeeded = errors.New("need more packets")
func joinFragments(fragments [][]byte, size int) []byte {
ret := make([]byte, size)
n := 0
for _, p := range fragments {
n += copy(ret[n:], p)
}
return ret
}
// Decoder is a RTP/MPEG-4 Audio decoder.
// Specification: https://datatracker.ietf.org/doc/html/rfc6416#section-7.3
type Decoder struct {
// StreamMuxConfig.
Config *mpeg4audio.StreamMuxConfig
timeDecoder *rtptime.Decoder
fragments [][]byte
fragmentsSize int
fragmentsExpected int
}
// Init initializes the decoder.
func (d *Decoder) Init() error {
if d.Config == nil || len(d.Config.Programs) != 1 || len(d.Config.Programs[0].Layers) != 1 {
return fmt.Errorf("unsupported StreamMuxConfig")
}
d.timeDecoder = rtptime.NewDecoder(d.Config.Programs[0].Layers[0].AudioSpecificConfig.SampleRate)
return nil
}
// Decode decodes an AU from a RTP packet.
// It returns the AU and its PTS.
func (d *Decoder) Decode(pkt *rtp.Packet) ([]byte, time.Duration, error) {
var au []byte
buf := pkt.Payload
if len(d.fragments) == 0 {
pl, n, err := payloadLengthInfoDecode(buf)
if err != nil {
return nil, 0, err
}
buf = buf[n:]
bl := len(buf)
if pl <= bl {
au = buf[:pl]
// there could be other data, due to otherDataPresent. Ignore it.
} else {
if pl > mpeg4audio.MaxAccessUnitSize {
d.fragments = d.fragments[:0] // discard pending fragments
return nil, 0, fmt.Errorf("access unit size (%d) is too big, maximum is %d",
pl, mpeg4audio.MaxAccessUnitSize)
}
d.fragments = append(d.fragments, buf)
d.fragmentsSize = pl
d.fragmentsExpected = pl - bl
return nil, 0, ErrMorePacketsNeeded
}
} else {
bl := len(buf)
if d.fragmentsExpected > bl {
d.fragments = append(d.fragments, buf)
d.fragmentsExpected -= bl
return nil, 0, ErrMorePacketsNeeded
}
d.fragments = append(d.fragments, buf[:d.fragmentsExpected])
// there could be other data, due to otherDataPresent. Ignore it.
au = joinFragments(d.fragments, d.fragmentsSize)
d.fragments = d.fragments[:0]
}
return au, d.timeDecoder.Decode(pkt.Timestamp), nil
}