-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
186 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
#include "clock.hpp" | ||
|
||
#include <QMutex> | ||
|
||
extern "C" { | ||
#include <libavutil/time.h> | ||
} | ||
|
||
namespace Ffmpeg { | ||
|
||
class Clock::ClockPrivate | ||
{ | ||
public: | ||
explicit ClockPrivate(Clock *q) | ||
: q_ptr(q) | ||
{} | ||
|
||
Clock *q_ptr; | ||
|
||
mutable QMutex mutex; | ||
qint64 pts = 0; // 当前 AVFrame 的时间戳 microseconds | ||
qint64 pts_drift = 0; // 时钟漂移量,用于计算当前时钟的状态 microseconds | ||
qint64 last_updated = av_gettime_relative(); // 上一次更新时钟状态的时间 microseconds | ||
bool paused = false; // 是否暂停播放 | ||
|
||
static constexpr QPair<double, double> speedRange = {0.5, 3.0}; | ||
static constexpr auto speedStep = 0.5; | ||
static std::atomic<double> speed; | ||
|
||
static constexpr auto diffThreshold = 50 * 1000; // 50ms | ||
|
||
static Clock *g_clock; | ||
}; | ||
|
||
std::atomic<double> Clock::ClockPrivate::speed = 1.0; | ||
Clock *Clock::ClockPrivate::g_clock = nullptr; | ||
|
||
Clock::Clock(QObject *parent) | ||
: QObject{parent} | ||
, d_ptr(new ClockPrivate(this)) | ||
{} | ||
|
||
Clock::~Clock() = default; | ||
|
||
auto Clock::pts() -> qint64 | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
return d_ptr->pts; | ||
} | ||
|
||
auto Clock::ptsDrift() -> qint64 | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
return d_ptr->pts_drift; | ||
} | ||
|
||
auto Clock::lastUpdated() -> qint64 | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
return d_ptr->last_updated; | ||
} | ||
|
||
auto Clock::paused() -> bool | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
return d_ptr->paused; | ||
} | ||
|
||
void Clock::setPaused(bool value) | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
d_ptr->paused = value; | ||
if (!d_ptr->paused) { | ||
d_ptr->last_updated = av_gettime_relative(); | ||
} | ||
} | ||
|
||
void Clock::update(qint64 pts, qint64 time) | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
if (d_ptr->last_updated && !d_ptr->paused) { | ||
qint64 time_diff = (time - d_ptr->last_updated) * speed(); | ||
d_ptr->pts_drift = (pts - d_ptr->pts) - time_diff; | ||
} | ||
d_ptr->pts = pts; | ||
d_ptr->last_updated = time; | ||
} | ||
|
||
auto Clock::getDelayWithMaster() -> qint64 | ||
{ | ||
Q_ASSERT(Clock::ClockPrivate::g_clock); | ||
auto pts_drift = ptsDrift(); | ||
if (this == Clock::ClockPrivate::g_clock) { | ||
return pts_drift; | ||
} | ||
pts_drift -= Clock::ClockPrivate::g_clock->ptsDrift(); | ||
return pts_drift; | ||
} | ||
|
||
auto Clock::adjustDelay(qint64 &delay) -> bool | ||
{ | ||
if (speed() > 1.0 && delay < 0) { | ||
return false; | ||
} else if (delay < -Clock::ClockPrivate::diffThreshold) { | ||
return false; | ||
} else if (qAbs(delay) <= Clock::ClockPrivate::diffThreshold) { | ||
delay = 0; | ||
return true; | ||
} | ||
delay -= Clock::ClockPrivate::diffThreshold; | ||
return true; | ||
} | ||
|
||
auto Clock::speedRange() -> QPair<double, double> | ||
{ | ||
return Clock::ClockPrivate::speedRange; | ||
} | ||
|
||
auto Clock::speedStep() -> double | ||
{ | ||
return Clock::ClockPrivate::speedStep; | ||
} | ||
|
||
void Clock::setSpeed(double value) | ||
{ | ||
Clock::ClockPrivate::speed.store(value); | ||
} | ||
|
||
auto Clock::speed() -> double | ||
{ | ||
return Clock::ClockPrivate::speed.load(); | ||
} | ||
|
||
void Clock::setMaster(Clock *clock) | ||
{ | ||
Clock::ClockPrivate::g_clock = clock; | ||
} | ||
|
||
} // namespace Ffmpeg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
#ifndef CLOCK_HPP | ||
#define CLOCK_HPP | ||
|
||
#include <QObject> | ||
|
||
namespace Ffmpeg { | ||
|
||
class Clock : public QObject | ||
{ | ||
public: | ||
explicit Clock(QObject *parent = nullptr); | ||
~Clock() override; | ||
|
||
auto pts() -> qint64; | ||
auto ptsDrift() -> qint64; | ||
auto lastUpdated() -> qint64; | ||
|
||
void setPaused(bool value); | ||
auto paused() -> bool; | ||
|
||
void update(qint64 pts, qint64 time); | ||
|
||
auto getDelayWithMaster() -> qint64; | ||
|
||
// return true if delay is valid | ||
static auto adjustDelay(qint64 &delay) -> bool; | ||
|
||
auto speedRange() -> QPair<double, double>; | ||
auto speedStep() -> double; | ||
static void setSpeed(double value); | ||
static auto speed() -> double; | ||
|
||
// not thread safe and not delete clock | ||
static void setMaster(Clock *clock); | ||
|
||
private: | ||
class ClockPrivate; | ||
QScopedPointer<ClockPrivate> d_ptr; | ||
}; | ||
|
||
} // namespace Ffmpeg | ||
|
||
#endif // CLOCK_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters