mirror of
https://github.com/bluenviron/mediamtx
synced 2025-02-10 00:18:22 +00:00
* 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
60 lines
1.4 KiB
Go
60 lines
1.4 KiB
Go
package hls
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
func durationGoToMp4(v time.Duration, timeScale uint32) uint64 {
|
|
timeScale64 := uint64(timeScale)
|
|
secs := v / time.Second
|
|
dec := v % time.Second
|
|
return uint64(secs)*timeScale64 + uint64(dec)*timeScale64/uint64(time.Second)
|
|
}
|
|
|
|
func durationMp4ToGo(v uint64, timeScale uint32) time.Duration {
|
|
timeScale64 := uint64(timeScale)
|
|
secs := v / timeScale64
|
|
dec := v % timeScale64
|
|
return time.Duration(secs)*time.Second + time.Duration(dec)*time.Second/time.Duration(timeScale64)
|
|
}
|
|
|
|
type clientTimeSyncFMP4 struct {
|
|
startRTC time.Time
|
|
startDTS time.Duration
|
|
}
|
|
|
|
func newClientTimeSyncFMP4(timeScale uint32, baseTime uint64) *clientTimeSyncFMP4 {
|
|
return &clientTimeSyncFMP4{
|
|
startRTC: time.Now(),
|
|
startDTS: durationMp4ToGo(baseTime, timeScale),
|
|
}
|
|
}
|
|
|
|
func (ts *clientTimeSyncFMP4) convertAndSync(ctx context.Context, timeScale uint32,
|
|
rawDTS uint64, ptsOffset int32,
|
|
) (time.Duration, error) {
|
|
pts := durationMp4ToGo(rawDTS+uint64(ptsOffset), timeScale)
|
|
dts := durationMp4ToGo(rawDTS, timeScale)
|
|
|
|
pts -= ts.startDTS
|
|
dts -= ts.startDTS
|
|
|
|
elapsed := time.Since(ts.startRTC)
|
|
if dts > elapsed {
|
|
diff := dts - elapsed
|
|
if diff > clientMaxDTSRTCDiff {
|
|
return 0, fmt.Errorf("difference between DTS and RTC is too big")
|
|
}
|
|
|
|
select {
|
|
case <-time.After(diff):
|
|
case <-ctx.Done():
|
|
return 0, fmt.Errorf("terminated")
|
|
}
|
|
}
|
|
|
|
return pts, nil
|
|
}
|