Browse Source
* split data into specialized structs * move MPEG4-audio decoding into streamTrack * restore video/audio synchronization in HLS muxer and RTMP server * log decode errors * move H264 decoding and re-encoding here from gortsplib * add tests * update gortsplibpull/1212/head
19 changed files with 860 additions and 246 deletions
@ -1,19 +1,33 @@
@@ -1,19 +1,33 @@
|
||||
package core |
||||
|
||||
import ( |
||||
"github.com/aler9/gortsplib" |
||||
"fmt" |
||||
) |
||||
|
||||
type streamTrackGeneric struct { |
||||
writeDataInner func(*data) |
||||
const ( |
||||
// 1500 (UDP MTU) - 20 (IP header) - 8 (UDP header)
|
||||
maxPacketSize = 1472 |
||||
) |
||||
|
||||
type streamTrackGeneric struct{} |
||||
|
||||
func newStreamTrackGeneric() *streamTrackGeneric { |
||||
return &streamTrackGeneric{} |
||||
} |
||||
|
||||
func newStreamTrackGeneric(track gortsplib.Track, writeDataInner func(*data)) *streamTrackGeneric { |
||||
return &streamTrackGeneric{ |
||||
writeDataInner: writeDataInner, |
||||
func (t *streamTrackGeneric) onData(dat data, hasNonRTSPReaders bool) error { |
||||
tdata := dat.(*dataGeneric) |
||||
|
||||
pkt := tdata.rtpPackets[0] |
||||
|
||||
// remove padding
|
||||
pkt.Header.Padding = false |
||||
pkt.PaddingSize = 0 |
||||
|
||||
if pkt.MarshalSize() > maxPacketSize { |
||||
return fmt.Errorf("payload size (%d) is greater than maximum allowed (%d)", |
||||
pkt.MarshalSize(), maxPacketSize) |
||||
} |
||||
} |
||||
|
||||
func (t *streamTrackGeneric) writeData(data *data) { |
||||
t.writeDataInner(data) |
||||
return nil |
||||
} |
||||
|
@ -1,58 +1,89 @@
@@ -1,58 +1,89 @@
|
||||
package core |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/aler9/gortsplib" |
||||
"github.com/aler9/gortsplib/pkg/rtpmpeg4audio" |
||||
) |
||||
|
||||
type streamTrackMPEG4Audio struct { |
||||
writeDataInner func(*data) |
||||
|
||||
rtpEncoder *rtpmpeg4audio.Encoder |
||||
track *gortsplib.TrackMPEG4Audio |
||||
encoder *rtpmpeg4audio.Encoder |
||||
decoder *rtpmpeg4audio.Decoder |
||||
} |
||||
|
||||
func newStreamTrackMPEG4Audio( |
||||
track *gortsplib.TrackMPEG4Audio, |
||||
generateRTPPackets bool, |
||||
writeDataInner func(*data), |
||||
) *streamTrackMPEG4Audio { |
||||
t := &streamTrackMPEG4Audio{ |
||||
writeDataInner: writeDataInner, |
||||
track: track, |
||||
} |
||||
|
||||
if generateRTPPackets { |
||||
t.rtpEncoder = &rtpmpeg4audio.Encoder{ |
||||
t.encoder = &rtpmpeg4audio.Encoder{ |
||||
PayloadType: 96, |
||||
SampleRate: track.ClockRate(), |
||||
SizeLength: 13, |
||||
IndexLength: 3, |
||||
IndexDeltaLength: 3, |
||||
} |
||||
t.rtpEncoder.Init() |
||||
t.encoder.Init() |
||||
} |
||||
|
||||
return t |
||||
} |
||||
|
||||
func (t *streamTrackMPEG4Audio) generateRTPPackets(dat *data) { |
||||
pkts, err := t.rtpEncoder.Encode([][]byte{dat.mpeg4AudioAU}, dat.pts) |
||||
func (t *streamTrackMPEG4Audio) generateRTPPackets(tdata *dataMPEG4Audio) error { |
||||
pkts, err := t.encoder.Encode(tdata.aus, tdata.pts) |
||||
if err != nil { |
||||
return |
||||
return err |
||||
} |
||||
|
||||
for _, pkt := range pkts { |
||||
t.writeDataInner(&data{ |
||||
trackID: dat.trackID, |
||||
rtpPacket: pkt, |
||||
ptsEqualsDTS: true, |
||||
}) |
||||
} |
||||
tdata.rtpPackets = pkts |
||||
return nil |
||||
} |
||||
|
||||
func (t *streamTrackMPEG4Audio) writeData(dat *data) { |
||||
if dat.rtpPacket != nil { |
||||
t.writeDataInner(dat) |
||||
} else { |
||||
t.generateRTPPackets(dat) |
||||
func (t *streamTrackMPEG4Audio) onData(dat data, hasNonRTSPReaders bool) error { |
||||
tdata := dat.(*dataMPEG4Audio) |
||||
|
||||
if tdata.rtpPackets != nil { |
||||
pkt := tdata.rtpPackets[0] |
||||
|
||||
// remove padding
|
||||
pkt.Header.Padding = false |
||||
pkt.PaddingSize = 0 |
||||
|
||||
if pkt.MarshalSize() > maxPacketSize { |
||||
return fmt.Errorf("payload size (%d) is greater than maximum allowed (%d)", |
||||
pkt.MarshalSize(), maxPacketSize) |
||||
} |
||||
|
||||
// decode from RTP
|
||||
if hasNonRTSPReaders { |
||||
if t.decoder == nil { |
||||
t.decoder = &rtpmpeg4audio.Decoder{ |
||||
SampleRate: t.track.Config.SampleRate, |
||||
SizeLength: t.track.SizeLength, |
||||
IndexLength: t.track.IndexLength, |
||||
IndexDeltaLength: t.track.IndexDeltaLength, |
||||
} |
||||
t.decoder.Init() |
||||
} |
||||
|
||||
aus, pts, err := t.decoder.Decode(pkt) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
tdata.aus = aus |
||||
tdata.pts = pts |
||||
} |
||||
|
||||
// route packet as is
|
||||
return nil |
||||
} |
||||
|
||||
return t.generateRTPPackets(tdata) |
||||
} |
||||
|
Loading…
Reference in new issue