forked from External/mediamtx
* hls source: support fMP4s video streams * hls source: start reading live streams from (end of playlist - starting point) * hls client: wait processing of current fMP4 segment before downloading another one * hls client: support fmp4 trun boxes with default sample duration, flags and size * hls client: merge fmp4 init file reader and writer * hls client: merge fmp4 part reader and writer * hls client: improve precision of go <-> mp4 time conversion * hls client: fix esds generation in go-mp4 * hls client: support audio in separate playlist * hls client: support an arbitrary number of tracks in fmp4 init files * hls client: support EXT-X-BYTERANGE * hls client: support fmp4 segments with multiple parts at once * hls client: support an arbitrary number of mpeg-ts tracks * hls client: synchronize tracks around a primary track * update go-mp4 * hls: synchronize track reproduction around a leading one * hls client: reset stream if playback is too late * hls client: add limit on DTS-RTC difference * hls client: support again streams that don't provide codecs in master playlist
70 lines
1.5 KiB
Go
70 lines
1.5 KiB
Go
package hls
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/aler9/rtsp-simple-server/internal/hls/fmp4"
|
|
)
|
|
|
|
type clientProcessorFMP4Track struct {
|
|
timeScale uint32
|
|
ts *clientTimeSyncFMP4
|
|
onPartTrackProcessed func(context.Context)
|
|
onEntry func(time.Duration, []byte) error
|
|
|
|
// in
|
|
queue chan *fmp4.PartTrack
|
|
}
|
|
|
|
func newClientProcessorFMP4Track(
|
|
timeScale uint32,
|
|
ts *clientTimeSyncFMP4,
|
|
onPartTrackProcessed func(context.Context),
|
|
onEntry func(time.Duration, []byte) error,
|
|
) *clientProcessorFMP4Track {
|
|
return &clientProcessorFMP4Track{
|
|
timeScale: timeScale,
|
|
ts: ts,
|
|
onPartTrackProcessed: onPartTrackProcessed,
|
|
onEntry: onEntry,
|
|
queue: make(chan *fmp4.PartTrack, clientFMP4MaxPartTracksPerSegment),
|
|
}
|
|
}
|
|
|
|
func (t *clientProcessorFMP4Track) run(ctx context.Context) error {
|
|
for {
|
|
select {
|
|
case entry := <-t.queue:
|
|
err := t.processPartTrack(ctx, entry)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
t.onPartTrackProcessed(ctx)
|
|
|
|
case <-ctx.Done():
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func (t *clientProcessorFMP4Track) processPartTrack(ctx context.Context, pt *fmp4.PartTrack) error {
|
|
rawDTS := pt.BaseTime
|
|
|
|
for _, sample := range pt.Samples {
|
|
pts, err := t.ts.convertAndSync(ctx, t.timeScale, rawDTS, sample.PTSOffset)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = t.onEntry(pts, sample.Payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
rawDTS += uint64(sample.Duration)
|
|
}
|
|
|
|
return nil
|
|
}
|