diff options
Diffstat (limited to 'src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp')
-rw-r--r-- | src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp new file mode 100644 index 000000000..8352384b4 --- /dev/null +++ b/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp @@ -0,0 +1,165 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "playbackengine/qffmpegtimecontroller_p.h" + +#include "qglobal.h" +#include "qdebug.h" + +#include <algorithm> + +QT_BEGIN_NAMESPACE + +namespace QFFmpeg { + +TimeController::TimeController() +{ + sync(); +} + +TimeController::PlaybackRate TimeController::playbackRate() const +{ + return m_playbackRate; +} + +void TimeController::setPlaybackRate(PlaybackRate playbackRate) +{ + if (playbackRate == m_playbackRate) + return; + + Q_ASSERT(playbackRate > 0.f); + + scrollTimeTillNow(); + m_playbackRate = playbackRate; + + if (m_softSyncData) + m_softSyncData = makeSoftSyncData(m_timePoint, m_position, m_softSyncData->dstTimePoint); +} + +void TimeController::sync(qint64 trackPos) +{ + sync(Clock::now(), trackPos); +} + +void TimeController::sync(const TimePoint &tp, qint64 pos) +{ + m_softSyncData.reset(); + m_position = TrackTime(pos); + m_timePoint = tp; +} + +void TimeController::syncSoft(const TimePoint &tp, qint64 pos, const Clock::duration &fixingTime) +{ + const auto srcTime = Clock::now(); + const auto srcPos = positionFromTime(srcTime, true); + const auto dstTime = srcTime + fixingTime; + + m_position = TrackTime(pos); + m_timePoint = tp; + + m_softSyncData = makeSoftSyncData(srcTime, TrackTime(srcPos), dstTime); +} + +qint64 TimeController::currentPosition(const Clock::duration &offset) const +{ + return positionFromTime(Clock::now() + offset); +} + +void TimeController::setPaused(bool paused) +{ + if (m_paused == paused) + return; + + scrollTimeTillNow(); + m_paused = paused; +} + +qint64 TimeController::positionFromTime(TimePoint tp, bool ignorePause) const +{ + tp = m_paused && !ignorePause ? m_timePoint : tp; + + if (m_softSyncData && tp < m_softSyncData->dstTimePoint) { + const PlaybackRate rate = + tp > m_softSyncData->srcTimePoint ? m_softSyncData->internalRate : m_playbackRate; + + return (m_softSyncData->srcPosition + + toTrackTime((tp - m_softSyncData->srcTimePoint) * rate)) + .count(); + } + + return positionFromTimeInternal(tp).count(); +} + +TimeController::TimePoint TimeController::timeFromPosition(qint64 pos, bool ignorePause) const +{ + auto position = m_paused && !ignorePause ? m_position : TrackTime(pos); + + if (m_softSyncData && position < m_softSyncData->dstPosition) { + const auto rate = position > m_softSyncData->srcPosition ? m_softSyncData->internalRate + : m_playbackRate; + return m_softSyncData->srcTimePoint + + toClockTime((position - m_softSyncData->srcPosition) / rate); + } + + return timeFromPositionInternal(position); +} + +TimeController::SoftSyncData TimeController::makeSoftSyncData(const TimePoint &srcTp, + const TrackTime &srcPos, + const TimePoint &dstTp) const +{ + SoftSyncData result; + result.srcTimePoint = srcTp; + result.srcPosition = srcPos; + result.dstTimePoint = dstTp; + result.srcPosOffest = srcPos - positionFromTimeInternal(srcTp); + result.dstPosition = positionFromTimeInternal(dstTp); + result.internalRate = + static_cast<PlaybackRate>(toClockTime(TrackTime(result.dstPosition - srcPos)).count()) + / (dstTp - srcTp).count(); + + return result; +} + +TimeController::TrackTime TimeController::positionFromTimeInternal(const TimePoint &tp) const +{ + return m_position + toTrackTime((tp - m_timePoint) * m_playbackRate); +} + +TimeController::TimePoint TimeController::timeFromPositionInternal(const TrackTime &pos) const +{ + return m_timePoint + toClockTime(TrackTime(pos - m_position) / m_playbackRate); +} + +void TimeController::scrollTimeTillNow() +{ + const auto now = Clock::now(); + if (!m_paused) { + m_position = positionFromTimeInternal(now); + + // let's forget outdated syncronizations + if (m_softSyncData && m_softSyncData->dstTimePoint <= now) + m_softSyncData.reset(); + } else if (m_softSyncData) { + m_softSyncData->dstTimePoint += now - m_timePoint; + m_softSyncData->srcTimePoint += now - m_timePoint; + } + + m_timePoint = now; +} + +template<typename T> +TimeController::Clock::duration TimeController::toClockTime(const T &t) +{ + return std::chrono::duration_cast<Clock::duration>(t); +} + +template<typename T> +TimeController::TrackTime TimeController::toTrackTime(const T &t) +{ + return std::chrono::duration_cast<TrackTime>(t); +} + +} // namespace QFFmpeg + +QT_END_NAMESPACE |