mediamtx/internal/hls/client_timesync_fmp4.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
}