Skip to content

Commit

Permalink
clock;
Browse files Browse the repository at this point in the history
  • Loading branch information
RealChuan committed Aug 25, 2023
1 parent 7a99b2b commit d0715a9
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 0 deletions.
2 changes: 2 additions & 0 deletions ffmpeg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ set(PROJECT_SOURCES
averror.h
averrormanager.cc
averrormanager.hpp
clock.cc
clock.hpp
codeccontext.cpp
codeccontext.h
colorspace.hpp
Expand Down
143 changes: 143 additions & 0 deletions ffmpeg/clock.cc
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
57 changes: 57 additions & 0 deletions ffmpeg/clock.hpp
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
2 changes: 2 additions & 0 deletions ffmpeg/ffmpeg.pro
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ SOURCES += \
avcontextinfo.cpp \
averror.cpp \
averrormanager.cc \
clock.cc \
codeccontext.cpp \
decoder.cc \
decoderaudioframe.cpp \
Expand All @@ -44,6 +45,7 @@ HEADERS += \
avcontextinfo.h \
averror.h \
averrormanager.hpp \
clock.hpp \
codeccontext.h \
colorspace.hpp \
decoder.h \
Expand Down

0 comments on commit d0715a9

Please sign in to comment.