Browse Source

update gortsplib (#2390)

pull/2391/head
Alessandro Ros 2 years ago committed by GitHub
parent
commit
d07ba5983e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      go.mod
  2. 4
      go.sum
  3. 42
      internal/core/hls_muxer.go
  4. 2
      internal/core/hls_source.go
  5. 2
      internal/core/mpegts.go
  6. 37
      internal/core/rtmp_conn.go
  7. 4
      internal/core/rtmp_source.go
  8. 29
      internal/core/srt_conn.go
  9. 18
      internal/formatprocessor/mpeg4_audio.go
  10. 112
      internal/formatprocessor/mpeg4_audio_latm.go
  11. 7
      internal/formatprocessor/processor.go
  12. 28
      internal/record/agent.go
  13. 2
      internal/record/agent_test.go
  14. 10
      internal/rtmp/writer.go
  15. 7
      internal/unit/mpeg4_audio.go
  16. 7
      internal/unit/mpeg4_audio_generic.go
  17. 7
      internal/unit/mpeg4_audio_latm.go

2
go.mod

@ -8,7 +8,7 @@ require ( @@ -8,7 +8,7 @@ require (
github.com/alecthomas/kong v0.8.0
github.com/aler9/writerseeker v1.1.0
github.com/bluenviron/gohlslib v1.0.3
github.com/bluenviron/gortsplib/v4 v4.1.1-0.20230919201539-fc2a10a4999a
github.com/bluenviron/gortsplib/v4 v4.1.1-0.20230921145131-44da79f72d5e
github.com/bluenviron/mediacommon v1.3.1-0.20230919191723-607668055ebe
github.com/datarhei/gosrt v0.5.4
github.com/fsnotify/fsnotify v1.6.0

4
go.sum

@ -14,8 +14,8 @@ github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYh @@ -14,8 +14,8 @@ github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYh
github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c/go.mod h1:x1vxHcL/9AVzuk5HOloOEPrtJY0MaalYr78afXZ+pWI=
github.com/bluenviron/gohlslib v1.0.3 h1:FMHevlIrrZ67uzCXmlTSGflsfYREEtHb8L9BDyf7lJc=
github.com/bluenviron/gohlslib v1.0.3/go.mod h1:R/aIsSxLI61N0CVMjtcHqJouK6+Ddd5YIihcCr7IFIw=
github.com/bluenviron/gortsplib/v4 v4.1.1-0.20230919201539-fc2a10a4999a h1:2zaPnmdTRJyfySBbRF8mCQDfOFOL2qQHfQFrLpKeyS0=
github.com/bluenviron/gortsplib/v4 v4.1.1-0.20230919201539-fc2a10a4999a/go.mod h1:0rVtKDafUA14isZuaBTm5+X9NPqLYs/lY8JIww6+doM=
github.com/bluenviron/gortsplib/v4 v4.1.1-0.20230921145131-44da79f72d5e h1:Y8b0vKPQLerALedmNNBmxrJR6sBcnge+fQeCH+Kfh3A=
github.com/bluenviron/gortsplib/v4 v4.1.1-0.20230921145131-44da79f72d5e/go.mod h1:0rVtKDafUA14isZuaBTm5+X9NPqLYs/lY8JIww6+doM=
github.com/bluenviron/mediacommon v1.3.1-0.20230919191723-607668055ebe h1:8kvIJfRXvv1Za1hdArKjvd/l8WCHJF+d+oLtANdFbr8=
github.com/bluenviron/mediacommon v1.3.1-0.20230919191723-607668055ebe/go.mod h1:/vlOVSebDwzdRtQONOKLua0fOSJg1tUDHpP+h9a0uqM=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=

42
internal/core/hls_muxer.go

@ -472,12 +472,12 @@ func (m *hlsMuxer) createAudioTrack(stream *stream.Stream) (*description.Media, @@ -472,12 +472,12 @@ func (m *hlsMuxer) createAudioTrack(stream *stream.Stream) (*description.Media,
}
}
var audioFormatMPEG4AudioGeneric *format.MPEG4AudioGeneric
audioMedia = stream.Desc().FindFormat(&audioFormatMPEG4AudioGeneric)
var audioFormatMPEG4Audio *format.MPEG4Audio
audioMedia = stream.Desc().FindFormat(&audioFormatMPEG4Audio)
if audioMedia != nil {
stream.AddReader(m.writer, audioMedia, audioFormatMPEG4AudioGeneric, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4AudioGeneric)
stream.AddReader(m.writer, audioMedia, audioFormatMPEG4Audio, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4Audio)
if tunit.AUs == nil {
return nil
@ -496,39 +496,7 @@ func (m *hlsMuxer) createAudioTrack(stream *stream.Stream) (*description.Media, @@ -496,39 +496,7 @@ func (m *hlsMuxer) createAudioTrack(stream *stream.Stream) (*description.Media,
return audioMedia, &gohlslib.Track{
Codec: &codecs.MPEG4Audio{
Config: *audioFormatMPEG4AudioGeneric.Config,
},
}
}
var audioFormatMPEG4AudioLATM *format.MPEG4AudioLATM
audioMedia = stream.Desc().FindFormat(&audioFormatMPEG4AudioLATM)
if audioMedia != nil &&
audioFormatMPEG4AudioLATM.Config != nil &&
len(audioFormatMPEG4AudioLATM.Config.Programs) == 1 &&
len(audioFormatMPEG4AudioLATM.Config.Programs[0].Layers) == 1 {
stream.AddReader(m.writer, audioMedia, audioFormatMPEG4AudioLATM, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4AudioLATM)
if tunit.AU == nil {
return nil
}
err := m.muxer.WriteMPEG4Audio(
tunit.NTP,
tunit.PTS,
[][]byte{tunit.AU})
if err != nil {
return fmt.Errorf("muxer error: %v", err)
}
return nil
})
return audioMedia, &gohlslib.Track{
Codec: &codecs.MPEG4Audio{
Config: *audioFormatMPEG4AudioLATM.Config.Programs[0].Layers[0].AudioSpecificConfig,
Config: *audioFormatMPEG4Audio.GetConfig(),
},
}
}

2
internal/core/hls_source.go

@ -168,7 +168,7 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan @@ -168,7 +168,7 @@ func (s *hlsSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan
}
c.OnDataMPEG4Audio(track, func(pts time.Duration, aus [][]byte) {
stream.WriteUnit(medi, medi.Formats[0], &unit.MPEG4AudioGeneric{
stream.WriteUnit(medi, medi.Formats[0], &unit.MPEG4Audio{
Base: unit.Base{
NTP: time.Now(),
PTS: pts,

2
internal/core/mpegts.go

@ -135,7 +135,7 @@ func mpegtsSetupTracks(r *mpegts.Reader, stream **stream.Stream) ([]*description @@ -135,7 +135,7 @@ func mpegtsSetupTracks(r *mpegts.Reader, stream **stream.Stream) ([]*description
}
r.OnDataMPEG4Audio(track, func(pts int64, aus [][]byte) error {
(*stream).WriteUnit(medi, medi.Formats[0], &unit.MPEG4AudioGeneric{
(*stream).WriteUnit(medi, medi.Formats[0], &unit.MPEG4Audio{
Base: unit.Base{
NTP: time.Now(),
PTS: decodeTime(pts),

37
internal/core/rtmp_conn.go

@ -395,12 +395,12 @@ func (c *rtmpConn) setupAudio( @@ -395,12 +395,12 @@ func (c *rtmpConn) setupAudio(
stream *stream.Stream,
writer *asyncwriter.Writer,
) (*description.Media, format.Format) {
var audioFormatMPEG4Generic *format.MPEG4AudioGeneric
audioMedia := stream.Desc().FindFormat(&audioFormatMPEG4Generic)
var audioFormatMPEG4Audio *format.MPEG4Audio
audioMedia := stream.Desc().FindFormat(&audioFormatMPEG4Audio)
if audioMedia != nil {
stream.AddReader(writer, audioMedia, audioFormatMPEG4Generic, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4AudioGeneric)
stream.AddReader(writer, audioMedia, audioFormatMPEG4Audio, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4Audio)
if tunit.AUs == nil {
return nil
@ -410,7 +410,7 @@ func (c *rtmpConn) setupAudio( @@ -410,7 +410,7 @@ func (c *rtmpConn) setupAudio(
c.nconn.SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout)))
err := (*w).WriteMPEG4Audio(
tunit.PTS+time.Duration(i)*mpeg4audio.SamplesPerAccessUnit*
time.Second/time.Duration(audioFormatMPEG4Generic.ClockRate()),
time.Second/time.Duration(audioFormatMPEG4Audio.ClockRate()),
au,
)
if err != nil {
@ -421,28 +421,7 @@ func (c *rtmpConn) setupAudio( @@ -421,28 +421,7 @@ func (c *rtmpConn) setupAudio(
return nil
})
return audioMedia, audioFormatMPEG4Generic
}
var audioFormatMPEG4AudioLATM *format.MPEG4AudioLATM
audioMedia = stream.Desc().FindFormat(&audioFormatMPEG4AudioLATM)
if audioMedia != nil &&
audioFormatMPEG4AudioLATM.Config != nil &&
len(audioFormatMPEG4AudioLATM.Config.Programs) == 1 &&
len(audioFormatMPEG4AudioLATM.Config.Programs[0].Layers) == 1 {
stream.AddReader(writer, audioMedia, audioFormatMPEG4AudioLATM, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4AudioLATM)
if tunit.AU == nil {
return nil
}
c.nconn.SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout)))
return (*w).WriteMPEG4Audio(tunit.PTS, tunit.AU)
})
return audioMedia, audioFormatMPEG4AudioLATM
return audioMedia, audioFormatMPEG4Audio
}
var audioFormatMPEG1 *format.MPEG1Audio
@ -590,9 +569,9 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error { @@ -590,9 +569,9 @@ func (c *rtmpConn) runPublish(conn *rtmp.Conn, u *url.URL) error {
medias = append(medias, audioMedia)
switch audioFormat.(type) {
case *format.MPEG4AudioGeneric:
case *format.MPEG4Audio:
r.OnDataMPEG4Audio(func(pts time.Duration, au []byte) {
stream.WriteUnit(audioMedia, audioFormat, &unit.MPEG4AudioGeneric{
stream.WriteUnit(audioMedia, audioFormat, &unit.MPEG4Audio{
Base: unit.Base{
NTP: time.Now(),
PTS: pts,

4
internal/core/rtmp_source.go

@ -148,9 +148,9 @@ func (s *rtmpSource) runReader(u *url.URL, nconn net.Conn) error { @@ -148,9 +148,9 @@ func (s *rtmpSource) runReader(u *url.URL, nconn net.Conn) error {
medias = append(medias, audioMedia)
switch audioFormat.(type) {
case *format.MPEG4AudioGeneric:
case *format.MPEG4Audio:
mc.OnDataMPEG4Audio(func(pts time.Duration, au []byte) {
stream.WriteUnit(audioMedia, audioFormat, &unit.MPEG4AudioGeneric{
stream.WriteUnit(audioMedia, audioFormat, &unit.MPEG4Audio{
Base: unit.Base{
NTP: time.Now(),
PTS: pts,

29
internal/core/srt_conn.go

@ -467,13 +467,13 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass @@ -467,13 +467,13 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass
return bw.Flush()
})
case *format.MPEG4AudioGeneric:
case *format.MPEG4Audio:
track := addTrack(medi, &mpegts.CodecMPEG4Audio{
Config: *forma.Config,
Config: *forma.GetConfig(),
})
res.stream.AddReader(writer, medi, forma, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4AudioGeneric)
tunit := u.(*unit.MPEG4Audio)
if tunit.AUs == nil {
return nil
}
@ -486,29 +486,6 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass @@ -486,29 +486,6 @@ func (c *srtConn) runRead(req srtNewConnReq, pathName string, user string, pass
return bw.Flush()
})
case *format.MPEG4AudioLATM:
if forma.Config != nil &&
len(forma.Config.Programs) == 1 &&
len(forma.Config.Programs[0].Layers) == 1 {
track := addTrack(medi, &mpegts.CodecMPEG4Audio{
Config: *forma.Config.Programs[0].Layers[0].AudioSpecificConfig,
})
res.stream.AddReader(writer, medi, forma, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4AudioLATM)
if tunit.AU == nil {
return nil
}
sconn.SetWriteDeadline(time.Now().Add(time.Duration(c.writeTimeout)))
err = w.WriteMPEG4Audio(track, durationGoToMPEGTS(tunit.PTS), [][]byte{tunit.AU})
if err != nil {
return err
}
return bw.Flush()
})
}
case *format.Opus:
track := addTrack(medi, &mpegts.CodecOpus{
ChannelCount: func() int {

18
internal/formatprocessor/mpeg4_audio_generic.go → internal/formatprocessor/mpeg4_audio.go

@ -11,19 +11,19 @@ import ( @@ -11,19 +11,19 @@ import (
"github.com/bluenviron/mediamtx/internal/unit"
)
type formatProcessorMPEG4AudioGeneric struct {
type formatProcessorMPEG4Audio struct {
udpMaxPayloadSize int
format *format.MPEG4Audio
encoder *rtpmpeg4audio.Encoder
decoder *rtpmpeg4audio.Decoder
}
func newMPEG4AudioGeneric(
func newMPEG4Audio(
udpMaxPayloadSize int,
forma *format.MPEG4Audio,
generateRTPPackets bool,
) (*formatProcessorMPEG4AudioGeneric, error) {
t := &formatProcessorMPEG4AudioGeneric{
) (*formatProcessorMPEG4Audio, error) {
t := &formatProcessorMPEG4Audio{
udpMaxPayloadSize: udpMaxPayloadSize,
format: forma,
}
@ -38,7 +38,7 @@ func newMPEG4AudioGeneric( @@ -38,7 +38,7 @@ func newMPEG4AudioGeneric(
return t, nil
}
func (t *formatProcessorMPEG4AudioGeneric) createEncoder() error {
func (t *formatProcessorMPEG4Audio) createEncoder() error {
t.encoder = &rtpmpeg4audio.Encoder{
PayloadMaxSize: t.udpMaxPayloadSize - 12,
PayloadType: t.format.PayloadTyp,
@ -49,8 +49,8 @@ func (t *formatProcessorMPEG4AudioGeneric) createEncoder() error { @@ -49,8 +49,8 @@ func (t *formatProcessorMPEG4AudioGeneric) createEncoder() error {
return t.encoder.Init()
}
func (t *formatProcessorMPEG4AudioGeneric) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.MPEG4AudioGeneric)
func (t *formatProcessorMPEG4Audio) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.MPEG4Audio)
pkts, err := t.encoder.Encode(u.AUs)
if err != nil {
@ -67,13 +67,13 @@ func (t *formatProcessorMPEG4AudioGeneric) ProcessUnit(uu unit.Unit) error { //n @@ -67,13 +67,13 @@ func (t *formatProcessorMPEG4AudioGeneric) ProcessUnit(uu unit.Unit) error { //n
return nil
}
func (t *formatProcessorMPEG4AudioGeneric) ProcessRTPPacket( //nolint:dupl
func (t *formatProcessorMPEG4Audio) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts time.Duration,
hasNonRTSPReaders bool,
) (Unit, error) {
u := &unit.MPEG4AudioGeneric{
u := &unit.MPEG4Audio{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,

112
internal/formatprocessor/mpeg4_audio_latm.go

@ -1,112 +0,0 @@ @@ -1,112 +0,0 @@
package formatprocessor
import (
"fmt"
"time"
"github.com/bluenviron/gortsplib/v4/pkg/format"
"github.com/bluenviron/gortsplib/v4/pkg/format/rtpmpeg4audiolatm"
"github.com/pion/rtp"
"github.com/bluenviron/mediamtx/internal/unit"
)
type formatProcessorMPEG4AudioLATM struct {
udpMaxPayloadSize int
format *format.MPEG4AudioLATM
encoder *rtpmpeg4audiolatm.Encoder
decoder *rtpmpeg4audiolatm.Decoder
}
func newMPEG4AudioLATM(
udpMaxPayloadSize int,
forma *format.MPEG4AudioLATM,
generateRTPPackets bool,
) (*formatProcessorMPEG4AudioLATM, error) {
t := &formatProcessorMPEG4AudioLATM{
udpMaxPayloadSize: udpMaxPayloadSize,
format: forma,
}
if generateRTPPackets {
err := t.createEncoder()
if err != nil {
return nil, err
}
}
return t, nil
}
func (t *formatProcessorMPEG4AudioLATM) createEncoder() error {
t.encoder = &rtpmpeg4audiolatm.Encoder{
PayloadType: t.format.PayloadTyp,
}
return t.encoder.Init()
}
func (t *formatProcessorMPEG4AudioLATM) ProcessUnit(uu unit.Unit) error { //nolint:dupl
u := uu.(*unit.MPEG4AudioLATM)
pkts, err := t.encoder.Encode(u.AU)
if err != nil {
return err
}
ts := uint32(multiplyAndDivide(u.PTS, time.Duration(t.format.ClockRate()), time.Second))
for _, pkt := range pkts {
pkt.Timestamp += ts
}
u.RTPPackets = pkts
return nil
}
func (t *formatProcessorMPEG4AudioLATM) ProcessRTPPacket( //nolint:dupl
pkt *rtp.Packet,
ntp time.Time,
pts time.Duration,
hasNonRTSPReaders bool,
) (Unit, error) {
u := &unit.MPEG4AudioLATM{
Base: unit.Base{
RTPPackets: []*rtp.Packet{pkt},
NTP: ntp,
PTS: pts,
},
}
// remove padding
pkt.Header.Padding = false
pkt.PaddingSize = 0
if pkt.MarshalSize() > t.udpMaxPayloadSize {
return nil, fmt.Errorf("payload size (%d) is greater than maximum allowed (%d)",
pkt.MarshalSize(), t.udpMaxPayloadSize)
}
// decode from RTP
if hasNonRTSPReaders || t.decoder != nil {
if t.decoder == nil {
var err error
t.decoder, err = t.format.CreateDecoder()
if err != nil {
return nil, err
}
}
au, err := t.decoder.Decode(pkt)
if err != nil {
if err == rtpmpeg4audiolatm.ErrMorePacketsNeeded {
return u, nil
}
return nil, err
}
u.AU = au
}
// route packet as is
return u, nil
}

7
internal/formatprocessor/processor.go

@ -63,11 +63,8 @@ func New( @@ -63,11 +63,8 @@ func New(
case *format.Opus:
return newOpus(udpMaxPayloadSize, forma, generateRTPPackets)
case *format.MPEG4AudioGeneric:
return newMPEG4AudioGeneric(udpMaxPayloadSize, forma, generateRTPPackets)
case *format.MPEG4AudioLATM:
return newMPEG4AudioLATM(udpMaxPayloadSize, forma, generateRTPPackets)
case *format.MPEG4Audio:
return newMPEG4Audio(udpMaxPayloadSize, forma, generateRTPPackets)
case *format.MPEG1Audio:
return newMPEG1Audio(udpMaxPayloadSize, forma, generateRTPPackets)

28
internal/record/agent.go

@ -571,16 +571,16 @@ func NewAgent( @@ -571,16 +571,16 @@ func NewAgent(
return nil
})
case *format.MPEG4AudioGeneric:
case *format.MPEG4Audio:
codec := &fmp4.CodecMPEG4Audio{
Config: *forma.Config,
Config: *forma.GetConfig(),
}
track := addTrack(codec)
sampleRate := time.Duration(forma.Config.SampleRate)
sampleRate := time.Duration(forma.ClockRate())
stream.AddReader(r.writer, media, forma, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4AudioGeneric)
tunit := u.(*unit.MPEG4Audio)
if tunit.AUs == nil {
return nil
}
@ -603,26 +603,6 @@ func NewAgent( @@ -603,26 +603,6 @@ func NewAgent(
return nil
})
case *format.MPEG4AudioLATM:
codec := &fmp4.CodecMPEG4Audio{
Config: *forma.Config.Programs[0].Layers[0].AudioSpecificConfig,
}
track := addTrack(codec)
stream.AddReader(r.writer, media, forma, func(u unit.Unit) error {
tunit := u.(*unit.MPEG4AudioLATM)
if tunit.AU == nil {
return nil
}
return track.record(&sample{
PartSample: &fmp4.PartSample{
Payload: tunit.AU,
},
dts: tunit.PTS,
})
})
case *format.MPEG1Audio:
codec := &fmp4.CodecMPEG1Audio{
SampleRate: 32000,

2
internal/record/agent_test.go

@ -132,7 +132,7 @@ func TestAgent(t *testing.T) { @@ -132,7 +132,7 @@ func TestAgent(t *testing.T) {
},
})
stream.WriteUnit(desc.Medias[2], desc.Medias[2].Formats[0], &unit.MPEG4AudioGeneric{
stream.WriteUnit(desc.Medias[2], desc.Medias[2].Formats[0], &unit.MPEG4Audio{
Base: unit.Base{
PTS: (50 + time.Duration(i)) * time.Second,
},

10
internal/rtmp/writer.go

@ -87,7 +87,7 @@ func (w *Writer) writeTracks(videoTrack format.Format, audioTrack format.Format) @@ -87,7 +87,7 @@ func (w *Writer) writeTracks(videoTrack format.Format, audioTrack format.Format)
case *format.MPEG1Audio:
return message.CodecMPEG1Audio
case *format.MPEG4AudioGeneric, *format.MPEG4AudioLATM:
case *format.MPEG4Audio:
return message.CodecMPEG4Audio
default:
@ -127,12 +127,8 @@ func (w *Writer) writeTracks(videoTrack format.Format, audioTrack format.Format) @@ -127,12 +127,8 @@ func (w *Writer) writeTracks(videoTrack format.Format, audioTrack format.Format)
var audioConfig *mpeg4audio.AudioSpecificConfig
switch track := audioTrack.(type) {
case *format.MPEG4Audio:
audioConfig = track.Config
case *format.MPEG4AudioLATM:
audioConfig = track.Config.Programs[0].Layers[0].AudioSpecificConfig
if track, ok := audioTrack.(*format.MPEG4Audio); ok {
audioConfig = track.GetConfig()
}
if audioConfig != nil {

7
internal/unit/mpeg4_audio.go

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
package unit
// MPEG4Audio is a MPEG-4 Audio data unit.
type MPEG4Audio struct {
Base
AUs [][]byte
}

7
internal/unit/mpeg4_audio_generic.go

@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
package unit
// MPEG4AudioGeneric is a MPEG-4 Audio data unit.
type MPEG4AudioGeneric struct {
Base
AUs [][]byte
}

7
internal/unit/mpeg4_audio_latm.go

@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
package unit
// MPEG4AudioLATM is a MPEG-4 Audio data unit.
type MPEG4AudioLATM struct {
Base
AU []byte
}
Loading…
Cancel
Save