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
|
|
}
|