module Data.ByteString.IsoBaseFileFormat.Util.Time
(referenceTime, utcToMp4, mp4CurrentTime, durationFromSeconds,
oneSecond32, oneSecond64, diffTimeToTicks,ticksToDiffTime,
TimeScale(..), Timing, TS(..), type TS32, type TS64, Ticks(..), Ticks32(..))
where
import Data.Time.Clock
import Data.Time.Calendar
import Data.Ratio
import Data.ByteString.IsoBaseFileFormat.Box
import Data.ByteString.IsoBaseFileFormat.Util.BoxFields
import Data.ByteString.IsoBaseFileFormat.Util.Versioned
import Data.ByteString.IsoBaseFileFormat.ReExports
import Data.Typeable
import Foreign.Storable
referenceTime :: UTCTime
referenceTime =
let startDay = fromGregorian 1904 1 1
startTime = 0
in UTCTime startDay startTime
utcToMp4 :: Num t
=> UTCTime -> t
utcToMp4 u =
let picoSecondsDiff = toRational $ diffUTCTime u referenceTime
picoSecondsDiffNumerator = numerator picoSecondsDiff
picoSecondsDiffDenominator = denominator picoSecondsDiff
secondsSinceReferenceTime =
div picoSecondsDiffNumerator picoSecondsDiffDenominator
in fromIntegral secondsSinceReferenceTime
diffTimeToTicks :: Integral t
=> NominalDiffTime -> TimeScale -> t
diffTimeToTicks !diff (TimeScale !scale) =
round (diff * (fromIntegral scale))
ticksToDiffTime :: Integral t
=> t -> TimeScale -> NominalDiffTime
ticksToDiffTime !t (TimeScale !scale) =
fromRational (toInteger t % toInteger scale)
mp4CurrentTime :: Num t
=> IO t
mp4CurrentTime = utcToMp4 <$> getCurrentTime
newtype TimeScale = TimeScale {fromTimeScale :: Word32}
deriving (Show,Eq,Num,Bounded,Ord,Bits,Integral,Typeable,Storable,Enum,Real)
instance Default TimeScale where
def = TimeScale 90000
instance IsBoxContent TimeScale where
boxSize = boxSize . fromTimeScale
boxBuilder = boxBuilder . fromTimeScale
durationFromSeconds :: Num t
=> TimeScale -> Integer -> t
durationFromSeconds timeScale seconds =
let timeScaleI = fromIntegral timeScale
in timeScaleI * fromInteger seconds
oneSecond32 = Scalar . flip durationFromSeconds 1
oneSecond32 :: TimeScale -> TS32 label
oneSecond64 :: TimeScale -> TS64 label
oneSecond64 = Scalar . flip durationFromSeconds 1
newtype Ticks (timeScale :: Nat) = MkTicks {fromTicks :: Word64}
deriving (Show,Eq,Num,Bounded,Ord,Bits,Integral,Typeable,Storable,Enum,Real)
instance IsBoxContent (Ticks n) where
boxSize = boxSize . fromTicks
boxBuilder = boxBuilder . fromTicks
newtype Ticks32 (timeScale :: Nat) = MkTicks32 {fromTicks32 :: Word32}
deriving (Show,Eq,Num,Bounded,Ord,Bits,Integral,Typeable,Storable,Enum,Real)
instance IsBoxContent (Ticks32 n) where
boxSize = boxSize . fromTicks32
boxBuilder = boxBuilder . fromTicks32
type Timing (version :: Nat) = Versioned TimingV0 TimingV1 version
type TS32 = Scalar Word32
type TS64 = Scalar Word64
data TS (version :: Nat) (label :: Symbol) where
TSv0 :: !Word32 -> TS 0 label
TSv1 :: !Word64 -> TS 1 label
instance IsBoxContent (TS v n) where
boxSize (TSv0 _t) = 4
boxSize (TSv1 _t) = 8
boxBuilder (TSv0 !t) = word32BE t
boxBuilder (TSv1 !t) = word64BE t
type TimingV0 = TimingImpl (Scalar Word32) (TS 0 "duration")
type TimingV1 = TimingImpl (Scalar Word64) (TS 1 "duration")
type TimingImpl uint dur =
uint "creation_time"
:+ uint "modification_time"
:+ TimeScale
:+ dur