-
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
204 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,143 @@ | ||
#include "clock.hpp" | ||
|
||
#include <QMutex> | ||
|
||
extern "C" { | ||
#include <libavutil/time.h> | ||
} | ||
|
||
namespace Ffmpeg { | ||
|
||
static Clock *g_clock = nullptr; | ||
|
||
class Clock::ClockPrivate | ||
{ | ||
public: | ||
explicit ClockPrivate(Clock *q) | ||
: q_ptr(q) | ||
{} | ||
|
||
Clock *q_ptr; | ||
|
||
mutable QMutex mutex; | ||
qint64 pts = 0; // 当前 AVFrame 的时间戳 | ||
qint64 pts_drift = 0; // 时钟漂移量,用于计算当前时钟的状态 | ||
qint64 last_updated = 0; // 上一次更新时钟状态的时间 | ||
double speed = 1.0; // 播放速度,用于调整音视频的播放速度 | ||
bool paused = false; // 是否暂停播放 | ||
|
||
static constexpr auto drop_threshold = 50 * 1000; // 50ms 丢帧阈值 | ||
static constexpr auto sync_threshold = 10 * 1000; // 10ms 同步阈值 | ||
}; | ||
|
||
Clock::Clock(QObject *parent) | ||
: QObject{parent} | ||
, d_ptr(new ClockPrivate(this)) | ||
{} | ||
|
||
Clock::~Clock() = default; | ||
|
||
auto Clock::getPts() -> qint64 | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
return d_ptr->pts; | ||
} | ||
|
||
auto Clock::getPtsDrift() -> qint64 | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
return d_ptr->pts_drift; | ||
} | ||
|
||
auto Clock::getLastUpdated() -> qint64 | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
return d_ptr->last_updated; | ||
} | ||
|
||
auto Clock::getSpeed() -> double | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
return d_ptr->speed; | ||
} | ||
|
||
void Clock::setSpeed(double value) | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
d_ptr->speed = value; | ||
} | ||
|
||
auto Clock::isPaused() -> bool | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
return d_ptr->paused; | ||
} | ||
|
||
void Clock::setPaused(bool value) | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
if (d_ptr->paused != value) { | ||
d_ptr->paused = value; | ||
if (d_ptr->paused) { | ||
d_ptr->last_updated = av_gettime_relative(); | ||
} | ||
} | ||
} | ||
|
||
void Clock::reset(qint64 pos) | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
d_ptr->pts = pos; | ||
d_ptr->pts_drift = av_gettime_relative(); | ||
d_ptr->last_updated = d_ptr->pts_drift; | ||
d_ptr->paused = false; | ||
} | ||
|
||
void Clock::update(qint64 pts, qint64 time) | ||
{ | ||
QMutexLocker locker(&d_ptr->mutex); | ||
if (d_ptr->last_updated && !d_ptr->paused) { | ||
// 计算时钟漂移量 | ||
d_ptr->pts_drift += (pts - d_ptr->pts) * d_ptr->speed + (time - d_ptr->last_updated); | ||
} | ||
// 更新当前 AVFrame 的时间戳和上一次更新时钟状态的时间 | ||
d_ptr->pts = pts; | ||
d_ptr->last_updated = time; | ||
} | ||
|
||
auto Clock::getClock(qint64 pts) -> qint64 | ||
{ | ||
Q_ASSERT(g_clock); | ||
|
||
QMutexLocker locker(&d_ptr->mutex); | ||
qint64 time = av_gettime_relative(); | ||
qint64 clock = d_ptr->pts_drift + pts * d_ptr->speed; | ||
if (d_ptr->paused) { | ||
clock = d_ptr->last_updated; | ||
} else { | ||
clock += time - d_ptr->last_updated; | ||
} | ||
// 计算全局时钟的状态与当前时钟的状态之间的差值 | ||
return clock + g_clock->getPtsDrift() - getPtsDrift(); | ||
} | ||
|
||
auto Clock::getDiff(qint64 &diff) -> bool | ||
{ | ||
qint64 clock = getClock(d_ptr->pts); | ||
diff = clock - av_gettime_relative(); | ||
if (diff <= -d_ptr->drop_threshold) { // 丢帧 | ||
d_ptr->pts_drift = clock - d_ptr->pts; | ||
return false; | ||
} else if (diff <= d_ptr->sync_threshold) { | ||
diff = 0; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
void Clock::setMaster(Clock *clock) | ||
{ | ||
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,57 @@ | ||
#ifndef CLOCK_HPP | ||
#define CLOCK_HPP | ||
|
||
#include <QObject> | ||
|
||
namespace Ffmpeg { | ||
|
||
class Clock : public QObject | ||
{ | ||
public: | ||
explicit Clock(QObject *parent = nullptr); | ||
~Clock() override; | ||
|
||
// 获取当前 AVFrame 的时间戳 | ||
auto getPts() -> qint64; | ||
|
||
// 获取时钟漂移量 | ||
auto getPtsDrift() -> qint64; | ||
|
||
// 获取上一次更新时钟状态的时间 | ||
auto getLastUpdated() -> qint64; | ||
|
||
// 获取播放速度 | ||
auto getSpeed() -> double; | ||
|
||
// 设置播放速度 | ||
void setSpeed(double value); | ||
|
||
// 获取是否暂停播放 | ||
auto isPaused() -> bool; | ||
|
||
// 设置是否暂停播放 | ||
void setPaused(bool value); | ||
|
||
// 重置时钟状态 | ||
void reset(qint64 pos); | ||
|
||
// 更新时钟状态 | ||
void update(qint64 pts, qint64 time); | ||
|
||
// 获取当前时钟的状态 | ||
auto getClock(qint64 pts) -> qint64; | ||
|
||
// 获取当前时钟的状态与上一次更新时钟状态的时间差 | ||
auto getDiff(qint64 &diff) -> bool; | ||
|
||
// not thread safe | ||
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