first commit
This commit is contained in:
275
project/fm_viewer/fav/AVClock.cpp
Normal file
275
project/fm_viewer/fav/AVClock.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/******************************************************************************
|
||||
QtAV: Multimedia framework based on Qt and FFmpeg
|
||||
Copyright (C) 2012-2016 Wang Bin <wbsecg1@gmail.com>
|
||||
|
||||
* This file is part of QtAV
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
******************************************************************************/
|
||||
#include "AVClock.h"
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QTimerEvent>
|
||||
#include <QtCore/QDateTime>
|
||||
#include "Logger.h"
|
||||
|
||||
namespace FAV {
|
||||
enum {
|
||||
kRunning,
|
||||
kPaused,
|
||||
kStopped
|
||||
};
|
||||
AVClock::AVClock(AVClock::ClockType c, QObject *parent):
|
||||
QObject(parent)
|
||||
, auto_clock(true)
|
||||
, m_state(kStopped)
|
||||
, clock_type(c)
|
||||
, mSpeed(1.0)
|
||||
, value0(0)
|
||||
, avg_err(0)
|
||||
, nb_restarted(0)
|
||||
, nb_sync(0)
|
||||
, sync_id(0)
|
||||
{
|
||||
last_pts = pts_ = pts_v = delay_ = 0;
|
||||
}
|
||||
|
||||
AVClock::AVClock(QObject *parent):
|
||||
QObject(parent)
|
||||
, auto_clock(true)
|
||||
, m_state(kStopped)
|
||||
, clock_type(AudioClock)
|
||||
, mSpeed(1.0)
|
||||
, value0(0)
|
||||
, avg_err(0)
|
||||
, nb_restarted(0)
|
||||
, nb_sync(0)
|
||||
, sync_id(0)
|
||||
{
|
||||
last_pts = pts_ = pts_v = delay_ = 0;
|
||||
}
|
||||
|
||||
void AVClock::setClockType(ClockType ct)
|
||||
{
|
||||
if (clock_type == ct)
|
||||
return;
|
||||
clock_type = ct;
|
||||
QTimer::singleShot(0, this, SLOT(restartCorrectionTimer()));
|
||||
}
|
||||
|
||||
AVClock::ClockType AVClock::clockType() const
|
||||
{
|
||||
return clock_type;
|
||||
}
|
||||
|
||||
bool AVClock::isActive() const
|
||||
{
|
||||
return clock_type == AudioClock || timer.isValid();
|
||||
}
|
||||
|
||||
void AVClock::setInitialValue(double v)
|
||||
{
|
||||
value0 = v;
|
||||
qDebug("Clock initial value: %f", v);
|
||||
}
|
||||
|
||||
double AVClock::initialValue() const
|
||||
{
|
||||
return value0;
|
||||
}
|
||||
|
||||
void AVClock::setClockAuto(bool a)
|
||||
{
|
||||
auto_clock = a;
|
||||
}
|
||||
|
||||
bool AVClock::isClockAuto() const
|
||||
{
|
||||
return auto_clock;
|
||||
}
|
||||
|
||||
void AVClock::updateExternalClock(qint64 msecs)
|
||||
{
|
||||
if (clock_type == AudioClock)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !(OFF_OTHER_DEBUG)
|
||||
qDebug("External clock change: %f ==> %f", value(), double(msecs) * kThousandth);
|
||||
#endif
|
||||
pts_ = double(msecs) * kThousandth; //can not use msec/1000.
|
||||
if (!isPaused())
|
||||
{
|
||||
timer.restart();
|
||||
}
|
||||
|
||||
last_pts = pts_;
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
if (clockType() == VideoClock)
|
||||
{
|
||||
pts_v = pts_;
|
||||
}
|
||||
}
|
||||
|
||||
void AVClock::updateExternalClock(const AVClock &clock)
|
||||
{
|
||||
if (clock_type != ExternalClock)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if !(OFF_OTHER_DEBUG)
|
||||
qDebug("External clock change: %f ==> %f", value(), clock.value());
|
||||
#endif
|
||||
pts_ = clock.value();
|
||||
|
||||
// qInfo() << "C:" << pts_;
|
||||
if (!isPaused())
|
||||
timer.restart();
|
||||
|
||||
last_pts = pts_;
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
void AVClock::setSpeed(qreal speed)
|
||||
{
|
||||
mSpeed = speed;
|
||||
}
|
||||
|
||||
bool AVClock::isPaused() const
|
||||
{
|
||||
return m_state == kPaused;
|
||||
}
|
||||
|
||||
// SYNC START 처리하면
|
||||
//
|
||||
int AVClock::syncStart(int count)
|
||||
{
|
||||
static int sId = 0;
|
||||
nb_sync = count;
|
||||
if (sId == -1) {
|
||||
sId = 0;
|
||||
}
|
||||
sync_id = ++sId;
|
||||
return sId;
|
||||
}
|
||||
|
||||
bool AVClock::syncEndOnce(int id)
|
||||
{
|
||||
if (id != sync_id)
|
||||
{
|
||||
qWarning("bad sync id: %d, current: %d", id, sync_id);
|
||||
return true;
|
||||
}
|
||||
if (!nb_sync.deref()) {
|
||||
sync_id = 0;
|
||||
}
|
||||
return sync_id;
|
||||
}
|
||||
|
||||
void AVClock::start()
|
||||
{
|
||||
m_state = kRunning;
|
||||
qDebug("AVClock started!!!!!!!!");
|
||||
timer.start();
|
||||
QTimer::singleShot(0, this, SLOT(restartCorrectionTimer()));
|
||||
Q_EMIT started();
|
||||
}
|
||||
//remember last value because we don't reset pts_, pts_v, delay_
|
||||
void AVClock::pause(bool p)
|
||||
{
|
||||
if (isPaused() == p)
|
||||
return;
|
||||
if (clock_type == AudioClock)
|
||||
return;
|
||||
m_state = p ? kPaused : kRunning;
|
||||
if (p) {
|
||||
QTimer::singleShot(0, this, SLOT(stopCorrectionTimer()));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
timer.invalidate();
|
||||
#else
|
||||
timer.stop();
|
||||
#endif //QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
Q_EMIT paused();
|
||||
} else {
|
||||
timer.start();
|
||||
QTimer::singleShot(0, this, SLOT(restartCorrectionTimer()));
|
||||
Q_EMIT resumed();
|
||||
}
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
Q_EMIT paused(p);
|
||||
}
|
||||
|
||||
void AVClock::reset()
|
||||
{
|
||||
nb_sync = 0;
|
||||
sync_id = 0;
|
||||
// keep mSpeed
|
||||
m_state = kStopped;
|
||||
value0 = 0;
|
||||
pts_ = pts_v = delay_ = 0;
|
||||
QTimer::singleShot(0, this, SLOT(stopCorrectionTimer()));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
timer.invalidate();
|
||||
#else
|
||||
timer.stop();
|
||||
#endif //QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
Q_EMIT resetted();
|
||||
}
|
||||
|
||||
void AVClock::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
Q_ASSERT_X(clockType() != AudioClock, "AVClock::timerEvent", "Internal error. AudioClock can not call this");
|
||||
if (event->timerId() != correction_schedule_timer.timerId())
|
||||
return;
|
||||
if (isPaused())
|
||||
return;
|
||||
const double delta_pts = (value() - last_pts)/speed();
|
||||
//const double err = double(correction_timer.restart()) * kThousandth - delta_pts;
|
||||
const qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
const double err = double(now - t) * kThousandth - delta_pts;
|
||||
t = now;
|
||||
// FIXME: avfoundation camera error is large (about -0.6s)
|
||||
if (qAbs(err*10.0) < kCorrectionInterval || clock_type == VideoClock) {
|
||||
avg_err += err/(nb_restarted+1);
|
||||
}
|
||||
//qDebug("correction timer event. error = %f, avg_err=%f, nb_restarted=%d", err, avg_err, nb_restarted);
|
||||
last_pts = value();
|
||||
nb_restarted = 0;
|
||||
}
|
||||
|
||||
void AVClock::restartCorrectionTimer()
|
||||
{
|
||||
nb_restarted = 0;
|
||||
avg_err = 0;
|
||||
correction_schedule_timer.stop();
|
||||
if (clockType() == AudioClock) // TODO: for all clock type
|
||||
return;
|
||||
// parameters are reset. do not start correction timer if not running
|
||||
if (m_state != kRunning)
|
||||
return;
|
||||
// timer is always started in AVClock::start()
|
||||
if (!timer.isValid())
|
||||
return;
|
||||
t = QDateTime::currentMSecsSinceEpoch();
|
||||
correction_schedule_timer.start(kCorrectionInterval*1000, this);
|
||||
}
|
||||
|
||||
void AVClock::stopCorrectionTimer()
|
||||
{
|
||||
nb_restarted = 0;
|
||||
avg_err = 0;
|
||||
correction_schedule_timer.stop();
|
||||
}
|
||||
} //namespace FAV
|
||||
Reference in New Issue
Block a user