first commit

This commit is contained in:
2026-02-21 17:11:31 +09:00
commit 18b4338361
4001 changed files with 365464 additions and 0 deletions

View 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