-- | Time and timing utilities. module Data.ByteString.IsoBaseFileFormat.Boxes.Time (referenceTime, utcToMp4, mp4CurrentTime, durationFromSeconds, TimeScale, Timing) where import Data.Time.Clock import Data.Time.Calendar import Data.Ratio import Data.ByteString.IsoBaseFileFormat.Boxes.Box import Data.ByteString.IsoBaseFileFormat.Boxes.BoxFields import Data.ByteString.IsoBaseFileFormat.Boxes.Versioned -- * Absolute Dates -- | According to the standard, fields with absolute dates and times are in -- seconds since 1904/01/01 at midnight (UTC). This is this reference time. referenceTime :: UTCTime referenceTime = let startDay = fromGregorian 1904 1 1 startTime = 0 in UTCTime startDay startTime -- | Convert a 'UTCTime' to a number of seconds since 'referenceTime'. 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 -- | Get the current time as number of seconds since 'referenceTime' mp4CurrentTime :: Num t => IO t mp4CurrentTime = utcToMp4 <$> getCurrentTime -- * Time-Scale and Durations -- | Default time-scale value -- Based on history and tradition this value is @90000@. -- MPEG-2 TS defines a single clock for each program, running at 27MHz. The -- timescale of MPEG-2 TS Hint Tracks should be divisable by 90000. type TimeScale = Template (U32 "timescale") 90000 -- | Utility function to convert seconds (Integers) to any 'Num' using a -- 'TimeScale', Since 'Scalar' has a 'Num' instance this can be used to generate -- @duration@ fields. durationFromSeconds :: Num t => TimeScale -> Integer -> t durationFromSeconds timeScale seconds = let timeScaleI = fromIntegral $ fromScalar $ templateValue timeScale in timeScaleI * fromInteger seconds -- | Time and timing information about a movie. -- -- The creation/modification times are in seconds since midnight, Jan. 1, 1904, -- in UTC time. Time scale declares the time coordinate system, it specifies the -- number of time units that pass one second. The time coordinate system is used -- by e.g. the duration field, which by the way contains the duration of the -- longest track, if known, or simply the equivalent of 1s. type Timing (version :: Nat) = Versioned TimingV0 TimingV1 version type TimingV0 = TimingImpl (Scalar Word32) type TimingV1 = TimingImpl (Scalar Word64) type TimingImpl uint = uint "creation_time" :+ uint "modification_time" :+ TimeScale :+ uint "duration"