mirror of
https://github.com/aler9/gortsplib
synced 2025-10-16 12:10:48 +08:00
96 lines
2.3 KiB
Go
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
|
|
}
|