Skip to content

Commit

Permalink
重写时钟,音视频同步代码;
Browse files Browse the repository at this point in the history
  • Loading branch information
RealChuan committed Aug 28, 2023
1 parent 7a99b2b commit 647fab8
Show file tree
Hide file tree
Showing 23 changed files with 643 additions and 604 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
17 changes: 2 additions & 15 deletions ffmpeg/audiodecoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,14 @@ AudioDecoder::AudioDecoder(QObject *parent)

AudioDecoder::~AudioDecoder() = default;

bool AudioDecoder::seek(qint64 seekTime)
{
if (!Decoder<PacketPtr>::seek(seekTime)) {
return false;
}
return d_ptr->decoderAudioFrame->seek(seekTime);
}

void AudioDecoder::pause(bool state)
{
d_ptr->decoderAudioFrame->pause(state);
}

void AudioDecoder::setVolume(qreal volume)
{
d_ptr->decoderAudioFrame->setVolume(volume);
}

void AudioDecoder::setIsLocalFile(bool isLocalFile)
void AudioDecoder::setMasterClock()
{
d_ptr->decoderAudioFrame->setIsLocalFile(isLocalFile);
d_ptr->decoderAudioFrame->setMasterClock();
}

void AudioDecoder::runDecoder()
Expand Down
6 changes: 1 addition & 5 deletions ffmpeg/audiodecoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@ class AudioDecoder : public Decoder<PacketPtr>
explicit AudioDecoder(QObject *parent = nullptr);
~AudioDecoder() override;

bool seek(qint64 seekTime) override;

void pause(bool state) override;

void setVolume(qreal volume);

void setIsLocalFile(bool isLocalFile);
void setMasterClock();

signals:
void positionChanged(qint64 position); // ms
Expand Down
180 changes: 180 additions & 0 deletions ffmpeg/clock.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#include "clock.hpp"

#include <QDebug>
#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
qint64 serial = s_serial.load(); // 时钟序列号 for seek
bool paused = false; // 是否暂停播放

static std::atomic<qint64> s_serial;
static constexpr QPair<double, double> s_speedRange = {0.5, 3.0};
static constexpr auto s_speedStep = 0.5;
static std::atomic<double> s_speed;
static constexpr auto s_diffThreshold = 50 * 1000; // 50 milliseconds
static Clock *s_clock;
};

std::atomic<qint64> Clock::ClockPrivate::s_serial = 0;
std::atomic<double> Clock::ClockPrivate::s_speed = 1.0;
Clock *Clock::ClockPrivate::s_clock = nullptr;

Clock::Clock(QObject *parent)
: QObject{parent}
, d_ptr(new ClockPrivate(this))
{}

Clock::~Clock() = default;

void Clock::reset()
{
QMutexLocker locker(&d_ptr->mutex);
d_ptr->pts = 0;
d_ptr->pts_drift = 0;
d_ptr->last_updated = av_gettime_relative();
d_ptr->serial = Clock::ClockPrivate::s_serial.load();
d_ptr->paused = false;
}

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;
}

void Clock::resetSerial()
{
QMutexLocker locker(&d_ptr->mutex);
d_ptr->serial = Clock::ClockPrivate::s_serial.load();
}

auto Clock::serial() -> qint64
{
QMutexLocker locker(&d_ptr->mutex);
return d_ptr->serial;
}

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)
{
Q_ASSERT(Clock::ClockPrivate::s_clock);

QMutexLocker locker(&d_ptr->mutex);
if (d_ptr->last_updated && !d_ptr->paused) {
if (this == Clock::ClockPrivate::s_clock) {
qint64 timediff = (time - d_ptr->last_updated) * speed();
d_ptr->pts_drift += pts - d_ptr->pts - timediff;
} else {
auto *masterClock = Clock::ClockPrivate::s_clock;
auto masterClockPts = masterClock->d_ptr->pts - masterClock->d_ptr->pts_drift;
qint64 timediff = (time - masterClock->d_ptr->last_updated) * speed();
d_ptr->pts_drift = pts - masterClockPts - timediff;
}
}
d_ptr->pts = pts;
d_ptr->last_updated = time;
}

auto Clock::getDelayWithMaster(qint64 &delay) -> bool
{
if (serial() != Clock::ClockPrivate::s_serial.load()) {
return false;
}
delay = ptsDrift();
return true;
}

auto Clock::adjustDelay(qint64 &delay) -> bool
{
if (speed() > 1.0 && delay < 0) {
return false;
} else if (delay < -Clock::ClockPrivate::s_diffThreshold) {
return false;
} else if (qAbs(delay) <= Clock::ClockPrivate::s_diffThreshold) {
delay = 0;
return true;
}
delay -= Clock::ClockPrivate::s_diffThreshold;
return true;
}

void Clock::globalSerialRef()
{
Clock::ClockPrivate::s_serial.fetch_add(1);
}

void Clock::globalSerialReset()
{
Clock::ClockPrivate::s_serial.store(0);
}

auto Clock::speedRange() -> QPair<double, double>
{
return Clock::ClockPrivate::s_speedRange;
}

auto Clock::speedStep() -> double
{
return Clock::ClockPrivate::s_speedStep;
}

void Clock::setSpeed(double value)
{
Clock::ClockPrivate::s_speed.store(value);
}

auto Clock::speed() -> double
{
return Clock::ClockPrivate::s_speed.load();
}

void Clock::setMaster(Clock *clock)
{
Clock::ClockPrivate::s_clock = clock;
}

} // namespace Ffmpeg
52 changes: 52 additions & 0 deletions ffmpeg/clock.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#ifndef CLOCK_HPP
#define CLOCK_HPP

#include <QObject>

namespace Ffmpeg {

class Clock : public QObject
{
public:
explicit Clock(QObject *parent = nullptr);
~Clock() override;

void reset();

auto pts() -> qint64;
auto ptsDrift() -> qint64;
auto lastUpdated() -> qint64;

void resetSerial();
auto serial() -> qint64;

void setPaused(bool value);
auto paused() -> bool;

void update(qint64 pts, qint64 time);

// return true if delay is valid
auto getDelayWithMaster(qint64 &delay) -> bool;

// return true if delay is valid
static auto adjustDelay(qint64 &delay) -> bool;

static void globalSerialRef();
static void globalSerialReset();

static auto speedRange() -> QPair<double, double>;
static 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
25 changes: 0 additions & 25 deletions ffmpeg/decoder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,4 @@ void calculateTime(Packet *packet, AVContextInfo *contextInfo)
// qDebug() << "Packet duration:" << duration << "pts:" << pts << "tb:" << tb.num << tb.den;
}

static std::atomic<qint64> g_meidaClock;

void setMediaClock(qint64 value)
{
g_meidaClock.store(value);
}

auto mediaClock() -> qint64
{
return g_meidaClock.load();
}

std::atomic<double> g_mediaSpeed = 1.0;

void setMediaSpeed(double speed)
{
Q_ASSERT(speed > 0);
g_mediaSpeed.store(speed);
}

auto mediaSpeed() -> double
{
return g_mediaSpeed.load();
}

} // namespace Ffmpeg
28 changes: 2 additions & 26 deletions ffmpeg/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,21 @@
#include "formatcontext.h"

#define Sleep_Queue_Full_Milliseconds 50
#define UnWait_Microseconds (50 * 1000)
#define Drop_Microseconds (-100 * 1000)

namespace Ffmpeg {

static const auto g_frameQueueSize = 25;
static const auto s_frameQueueSize = 25;

void calculateTime(Frame *frame, AVContextInfo *contextInfo, FormatContext *formatContext);
void calculateTime(Packet *packet, AVContextInfo *contextInfo);

void setMediaClock(qint64 value);
auto mediaClock() -> qint64;

void setMediaSpeed(double speed);
auto mediaSpeed() -> double;

template<typename T>
class Decoder : public QThread
{
public:
explicit Decoder(QObject *parent = nullptr)
: QThread(parent)
, m_queue(g_frameQueueSize)
, m_queue(s_frameQueueSize)
{}
~Decoder() override { stopDecoder(); }

Expand All @@ -55,7 +47,6 @@ class Decoder : public QThread
quit();
wait();
}
m_seekTime = 0;
}

void append(const T &t) { m_queue.put(t); }
Expand All @@ -67,20 +58,6 @@ class Decoder : public QThread

void wakeup() { m_queue.put(T()); }

virtual void pause(bool state) = 0;

virtual bool seek(qint64 seekTime) // microsecond
{
clear();
m_seekTime = seekTime;
assertVaild();
if (!m_contextInfo->isIndexVaild()) {
return false;
}
pause(false);
return true;
}

protected:
virtual void runDecoder() = 0;

Expand All @@ -103,7 +80,6 @@ class Decoder : public QThread
AVContextInfo *m_contextInfo = nullptr;
FormatContext *m_formatContext = nullptr;
std::atomic_bool m_runing = true;
qint64 m_seekTime = 0; // microsecond
};

} // namespace Ffmpeg
Expand Down
Loading

0 comments on commit 647fab8

Please sign in to comment.