/***************************************************************************** * Time.hpp: Adaptative streaming time definitions ***************************************************************************** * Copyright © 2015 - VideoLAN and VLC Authors * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifndef TIME_HPP #define TIME_HPP #include #include namespace adaptive { /* Scaled time */ using stime_t = int64_t; class Timescale { public: Timescale(uint64_t v = 0) : scale(v) {} vlc_tick_t ToTime(stime_t t) const { if( !scale ) return 0; stime_t v = t / scale; stime_t r = t % scale; return v * 1000000 + r * 1000000 / scale; } stime_t ToScaled(vlc_tick_t t) const { vlc_tick_t v = t / 1000000; vlc_tick_t r = t % 1000000; return v * scale + r * scale / 1000000; } bool isValid() const { return !!scale; } operator uint64_t() const { return scale; } private: uint64_t scale; }; class SegmentTimes { public: SegmentTimes() { demux = VLC_TICK_INVALID; media = VLC_TICK_INVALID; display = VLC_TICK_INVALID; } SegmentTimes(vlc_tick_t a, vlc_tick_t b, vlc_tick_t c = VLC_TICK_INVALID) { demux = a; media = b; display = c; } void offsetBy(vlc_tick_t v) { if(v == 0) return; if(demux != VLC_TICK_INVALID) demux += v; if(media != VLC_TICK_INVALID) media += v; if(display != VLC_TICK_INVALID) display += v; } vlc_tick_t demux; vlc_tick_t media; vlc_tick_t display; }; class Times { public: Times() { continuous = VLC_TICK_INVALID; } Times(const SegmentTimes &s, vlc_tick_t a) { segment = s; continuous = a; } void offsetBy(vlc_tick_t v) { if(continuous != VLC_TICK_INVALID) continuous += v; segment.offsetBy(v); } vlc_tick_t continuous; SegmentTimes segment; }; using SynchronizationReference = std::pair; class SynchronizationReferences { public: SynchronizationReferences() = default; void addReference(uint64_t seq, const Times &t) { for(auto &r : refs) if(r.first == seq) { /* update reference when the timestamps are really old to prevent false roll */ constexpr vlc_tick_t quarterroll = (INT64_C(0x1FFFFFFFF) * 100 / 9) >> 2; if(t.continuous - r.second.continuous > quarterroll) r.second = t; return; } while(refs.size() > 10) refs.pop_back(); refs.push_front(SynchronizationReference(seq, t)); } bool getReference(uint64_t seq, mtime_t, SynchronizationReference &ref) const { for(auto t : refs) { if(t.first != seq) continue; ref = t; return true; } return false; } private: std::list refs; }; } #endif // TIME_HPP