summaryrefslogtreecommitdiffstats
path: root/src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp')
-rw-r--r--src/plugins/multimedia/ffmpeg/playbackengine/qffmpegtimecontroller.cpp165
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