|
|
@@ -1,1537 +0,0 @@
|
|
|
-#include "utils_synchronizer_v2.h"
|
|
|
-#include "../base/logger.h"
|
|
|
-#include <algorithm>
|
|
|
-#include <cmath>
|
|
|
-#include <sstream>
|
|
|
-#include <iomanip>
|
|
|
-
|
|
|
-namespace av {
|
|
|
-namespace utils {
|
|
|
-SynchronizerV2::SynchronizerV2(const SyncConfigV2& config)
|
|
|
- : config_(config)
|
|
|
- , state_(SyncState::IDLE)
|
|
|
- , masterClockType_(ClockType::AUDIO)
|
|
|
- , initialized_(false)
|
|
|
- , running_(false)
|
|
|
- , paused_(false)
|
|
|
- , recoveryAttempts_(0)
|
|
|
- , lastSyncError_(0.0)
|
|
|
-{
|
|
|
- // 初始化时钟
|
|
|
- audioClock_ = ClockInfo();
|
|
|
- videoClock_ = ClockInfo();
|
|
|
- externalClock_ = ClockInfo();
|
|
|
-
|
|
|
- // 初始化历史记录
|
|
|
- audioClockHistory_.clear();
|
|
|
- videoClockHistory_.clear();
|
|
|
- syncErrorHistory_.clear();
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 created with strategy: " +
|
|
|
- std::to_string(static_cast<int>(config_.strategy)));
|
|
|
-}
|
|
|
-
|
|
|
-SynchronizerV2::~SynchronizerV2() {
|
|
|
- close();
|
|
|
- Logger::instance().info("SynchronizerV2 destroyed");
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::initialize() {
|
|
|
- if (initialized_) {
|
|
|
- return ErrorCode::ALREADY_INITIALIZED;
|
|
|
- }
|
|
|
-
|
|
|
- std::lock_guard<std::mutex> clockLock(clockMutex_);
|
|
|
- std::lock_guard<std::mutex> statsLock(statsMutex_);
|
|
|
-
|
|
|
- // 重置所有时钟
|
|
|
- resetClock(ClockType::AUDIO);
|
|
|
- resetClock(ClockType::VIDEO);
|
|
|
- resetClock(ClockType::EXTERNAL);
|
|
|
-
|
|
|
- // 选择主时钟
|
|
|
- selectMasterClock();
|
|
|
-
|
|
|
- // 重置统计信息
|
|
|
- stats_ = SyncStatsV2();
|
|
|
- stats_.lastUpdateTime = std::chrono::steady_clock::now();
|
|
|
-
|
|
|
- // 设置开始时间
|
|
|
- startTime_ = std::chrono::steady_clock::now();
|
|
|
- lastClockUpdate_ = startTime_;
|
|
|
- lastStatsUpdate_ = startTime_;
|
|
|
-
|
|
|
- state_ = SyncState::IDLE;
|
|
|
- initialized_ = true;
|
|
|
- recoveryAttempts_ = 0;
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 initialized");
|
|
|
- return ErrorCode::SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::start() {
|
|
|
- if (!initialized_) {
|
|
|
- return ErrorCode::NOT_INITIALIZED;
|
|
|
- }
|
|
|
-
|
|
|
- if (running_) {
|
|
|
- return ErrorCode::ALREADY_STARTED;
|
|
|
- }
|
|
|
-
|
|
|
- running_ = true;
|
|
|
- paused_ = false;
|
|
|
- state_ = SyncState::INITIALIZING;
|
|
|
-
|
|
|
- startTime_ = std::chrono::steady_clock::now();
|
|
|
- lastClockUpdate_ = startTime_;
|
|
|
-
|
|
|
- // 按照packets_sync.cpp的init_clock逻辑初始化外部时钟
|
|
|
- // 外部时钟应该初始化为NAN,而不是系统时间
|
|
|
- {
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
- if (std::isnan(externalClock_.pts)) {
|
|
|
- // 严格按照packets_sync.cpp的init_clock实现
|
|
|
- // 外部时钟初始化为NAN,不使用系统时间
|
|
|
- double currentTime = av_gettime_relative() / 1000000.0;
|
|
|
- externalClock_.pts = std::numeric_limits<double>::quiet_NaN(); // 初始化为NAN
|
|
|
- externalClock_.pts_drift = 0.0; // 初始化pts_drift
|
|
|
- externalClock_.lastUpdate = currentTime;
|
|
|
- externalClock_.speed = 1.0;
|
|
|
- externalClock_.serial = -1;
|
|
|
- externalClock_.paused = false;
|
|
|
- externalClock_.time = currentTime;
|
|
|
- externalClock_.drift = 0.0;
|
|
|
- externalClock_.smoothedPts = std::numeric_limits<double>::quiet_NaN();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 启动后立即进入同步状态
|
|
|
- state_ = SyncState::SYNCING;
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 started");
|
|
|
- return ErrorCode::SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setStreamInfo(bool hasAudio, bool hasVideo) {
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
- hasAudioStream_ = hasAudio;
|
|
|
- hasVideoStream_ = hasVideo;
|
|
|
-
|
|
|
- Logger::instance().info("Stream info updated: hasAudio=" + std::to_string(hasAudio) +
|
|
|
- ", hasVideo=" + std::to_string(hasVideo));
|
|
|
-
|
|
|
- // 重新选择主时钟
|
|
|
- selectMasterClock();
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::stop() {
|
|
|
- if (!running_) {
|
|
|
- return ErrorCode::NOT_STARTED;
|
|
|
- }
|
|
|
-
|
|
|
- running_ = false;
|
|
|
- paused_ = false;
|
|
|
- state_ = SyncState::IDLE;
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 stopped");
|
|
|
- return ErrorCode::SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::pause() {
|
|
|
- if (!running_) {
|
|
|
- return ErrorCode::NOT_STARTED;
|
|
|
- }
|
|
|
-
|
|
|
- if (paused_) {
|
|
|
- return ErrorCode::ALREADY_PAUSED;
|
|
|
- }
|
|
|
-
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
-
|
|
|
- paused_ = true;
|
|
|
-
|
|
|
- // 暂停所有时钟
|
|
|
- pauseClock(ClockType::AUDIO, true);
|
|
|
- pauseClock(ClockType::VIDEO, true);
|
|
|
- pauseClock(ClockType::EXTERNAL, true);
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 paused");
|
|
|
- return ErrorCode::SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::resume() {
|
|
|
- if (!running_) {
|
|
|
- return ErrorCode::NOT_STARTED;
|
|
|
- }
|
|
|
-
|
|
|
- if (!paused_) {
|
|
|
- return ErrorCode::NOT_PAUSED;
|
|
|
- }
|
|
|
-
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
-
|
|
|
- paused_ = false;
|
|
|
-
|
|
|
- // 恢复所有时钟
|
|
|
- pauseClock(ClockType::AUDIO, false);
|
|
|
- pauseClock(ClockType::VIDEO, false);
|
|
|
- pauseClock(ClockType::EXTERNAL, false);
|
|
|
-
|
|
|
- state_ = SyncState::SYNCING;
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 resumed");
|
|
|
- return ErrorCode::SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::reset() {
|
|
|
- std::lock_guard<std::mutex> clockLock(clockMutex_);
|
|
|
- std::lock_guard<std::mutex> statsLock(statsMutex_);
|
|
|
- std::lock_guard<std::mutex> historyLock(historyMutex_);
|
|
|
-
|
|
|
- // 重置时钟
|
|
|
- resetClock(ClockType::AUDIO);
|
|
|
- resetClock(ClockType::VIDEO);
|
|
|
- resetClock(ClockType::EXTERNAL);
|
|
|
-
|
|
|
- // 重置统计信息
|
|
|
- stats_ = SyncStatsV2();
|
|
|
- stats_.lastUpdateTime = std::chrono::steady_clock::now();
|
|
|
-
|
|
|
- // 清空历史记录
|
|
|
- audioClockHistory_.clear();
|
|
|
- videoClockHistory_.clear();
|
|
|
- syncErrorHistory_.clear();
|
|
|
-
|
|
|
- // 重置状态
|
|
|
- state_ = running_ ? SyncState::SYNCING : SyncState::IDLE;
|
|
|
- recoveryAttempts_ = 0;
|
|
|
- lastSyncError_ = 0.0;
|
|
|
-
|
|
|
- // 重新选择主时钟
|
|
|
- selectMasterClock();
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 reset");
|
|
|
- return ErrorCode::SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::close() {
|
|
|
- if (running_) {
|
|
|
- stop();
|
|
|
- }
|
|
|
-
|
|
|
- initialized_ = false;
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 closed");
|
|
|
- return ErrorCode::SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::setAudioClock(int64_t pts, double timeBase, int serial) {
|
|
|
- return updateClock(ClockType::AUDIO, pts, timeBase, serial);
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::setVideoClock(int64_t pts, double timeBase, int serial) {
|
|
|
- return updateClock(ClockType::VIDEO, pts, timeBase, serial);
|
|
|
-}
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::setExternalClock(int64_t pts, double timeBase, int serial) {
|
|
|
- return updateClock(ClockType::EXTERNAL, pts, timeBase, serial);
|
|
|
-}
|
|
|
-
|
|
|
-int64_t SynchronizerV2::getAudioClock(bool predict) const {
|
|
|
- return getClock(ClockType::AUDIO, predict);
|
|
|
-}
|
|
|
-
|
|
|
-int64_t SynchronizerV2::getVideoClock(bool predict) const {
|
|
|
- return getClock(ClockType::VIDEO, predict);
|
|
|
-}
|
|
|
-
|
|
|
-int64_t SynchronizerV2::getExternalClock(bool predict) const {
|
|
|
- return getClock(ClockType::EXTERNAL, predict);
|
|
|
-}
|
|
|
-
|
|
|
-int64_t SynchronizerV2::getMasterClock(bool predict) const {
|
|
|
- return getClock(masterClockType_, predict);
|
|
|
-}
|
|
|
-
|
|
|
-FrameDecision SynchronizerV2::shouldDisplayVideoFrame(int64_t pts, double timeBase, double duration) {
|
|
|
- FrameDecision decision;
|
|
|
- decision.actualPts = pts;
|
|
|
-
|
|
|
- if (!running_ || paused_) {
|
|
|
- decision.action = FrameAction::DELAY;
|
|
|
- decision.delay = 0.01; // 10ms
|
|
|
- decision.reason = paused_ ? "Paused" : "Not running";
|
|
|
- return decision;
|
|
|
- }
|
|
|
-
|
|
|
- // 参考AVPlayer2的视频帧显示决策算法
|
|
|
- double delay = duration > 0 ? duration : (1.0 / 25.0); // 默认25fps
|
|
|
-
|
|
|
- // 如果视频是主时钟,直接显示
|
|
|
- if (masterClockType_ == ClockType::VIDEO) {
|
|
|
- decision.action = FrameAction::DISPLAY;
|
|
|
- decision.delay = delay;
|
|
|
- decision.reason = "Video master";
|
|
|
- decision.targetPts = pts;
|
|
|
- return decision;
|
|
|
- }
|
|
|
-
|
|
|
- // 获取主时钟并计算同步误差
|
|
|
- int64_t masterClock = getMasterClock(false); // 不使用预测,获取当前值
|
|
|
- decision.targetPts = masterClock;
|
|
|
-
|
|
|
- double videoPts = ptsToSeconds(pts, timeBase);
|
|
|
- double masterPts = ptsToSeconds(masterClock, timeBase);
|
|
|
- double diff = videoPts - masterPts;
|
|
|
- decision.syncError = diff;
|
|
|
-
|
|
|
- // 添加调试日志(仅在同步误差较大时)
|
|
|
- if (std::abs(diff) > 1.0) { // 超过1秒时记录
|
|
|
- Logger::instance().warning("Large video sync error: videoPTS=" +
|
|
|
- std::to_string(videoPts) + "s, masterPTS=" +
|
|
|
- std::to_string(masterPts) + "s, diff=" +
|
|
|
- std::to_string(diff) + "s, masterClock=" +
|
|
|
- std::to_string(masterClock) + ", timeBase=" +
|
|
|
- std::to_string(timeBase));
|
|
|
- }
|
|
|
-
|
|
|
- // 参考packets_sync.cpp的AV_NOSYNC_THRESHOLD检查
|
|
|
- if (std::isnan(diff) || std::isinf(diff) || std::abs(diff) >= config_.noSyncThreshold) {
|
|
|
- // 同步误差过大,强制显示帧,不进行同步校正
|
|
|
- decision.action = FrameAction::DISPLAY;
|
|
|
- decision.delay = delay;
|
|
|
- decision.reason = "Large sync error, force display (diff: " + std::to_string(diff * 1000) + "ms)";
|
|
|
- decision.targetPts = pts;
|
|
|
-
|
|
|
- Logger::instance().warningf(
|
|
|
- "Video sync error exceeds AV_NOSYNC_THRESHOLD: " + std::to_string(diff * 1000) + "ms");
|
|
|
- return decision;
|
|
|
- }
|
|
|
-
|
|
|
- // 参考AVPlayer2的compute_target_delay算法进行同步调整
|
|
|
- double sync_threshold = std::max(config_.syncThreshold, std::min(0.1, delay));
|
|
|
-
|
|
|
- // 检查差异是否在合理范围内(避免异常值)
|
|
|
- if (!std::isnan(diff) && std::abs(diff) < config_.maxSyncError) {
|
|
|
- if (diff <= -sync_threshold) {
|
|
|
- // 视频落后太多,丢帧追赶
|
|
|
- decision.action = FrameAction::DROP;
|
|
|
- decision.reason = "Video too slow, drop frame";
|
|
|
-
|
|
|
- // 通知丢帧
|
|
|
- if (frameDropCallback_) {
|
|
|
- frameDropCallback_(ClockType::VIDEO, pts);
|
|
|
- }
|
|
|
-
|
|
|
- // 更新统计
|
|
|
- std::lock_guard<std::mutex> lock(statsMutex_);
|
|
|
- stats_.droppedFrames++;
|
|
|
-
|
|
|
- } else if (diff >= sync_threshold && delay > config_.frameDupThreshold) {
|
|
|
- // 视频超前且延迟足够大,增加延迟
|
|
|
- decision.action = FrameAction::DELAY;
|
|
|
- decision.delay = delay + diff;
|
|
|
- decision.reason = "Video too fast, increase delay";
|
|
|
-
|
|
|
- } else if (diff >= sync_threshold) {
|
|
|
- // 视频超前但延迟较小,重复帧
|
|
|
- decision.action = FrameAction::Frame_DUPLICATE;
|
|
|
- decision.delay = 2 * delay;
|
|
|
- decision.reason = "Video too fast, duplicate frame";
|
|
|
-
|
|
|
- // 通知重复帧
|
|
|
- if (frameDuplicateCallback_) {
|
|
|
- frameDuplicateCallback_(ClockType::VIDEO, pts);
|
|
|
- }
|
|
|
-
|
|
|
- // 更新统计
|
|
|
- std::lock_guard<std::mutex> lock(statsMutex_);
|
|
|
- stats_.duplicatedFrames++;
|
|
|
-
|
|
|
- } else {
|
|
|
- // 正常显示
|
|
|
- decision.action = FrameAction::DISPLAY;
|
|
|
- decision.delay = delay;
|
|
|
- decision.reason = "Normal display";
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 同步误差过大或异常,需要智能处理
|
|
|
- if (std::isnan(diff) || std::isinf(diff)) {
|
|
|
- // 异常值,强制显示
|
|
|
- decision.action = FrameAction::DISPLAY;
|
|
|
- decision.delay = delay;
|
|
|
- decision.reason = "Invalid sync value, force display";
|
|
|
- } else if (diff < -config_.maxSyncError) {
|
|
|
- // 视频严重落后,丢帧追赶
|
|
|
- decision.action = FrameAction::DROP;
|
|
|
- decision.reason = "Video severely behind, drop frame";
|
|
|
-
|
|
|
- // 通知丢帧
|
|
|
- if (frameDropCallback_) {
|
|
|
- frameDropCallback_(ClockType::VIDEO, pts);
|
|
|
- }
|
|
|
-
|
|
|
- // 更新统计
|
|
|
- std::lock_guard<std::mutex> lock(statsMutex_);
|
|
|
- stats_.droppedFrames++;
|
|
|
- } else if (diff > config_.maxSyncError) {
|
|
|
- // 视频严重超前,大幅延迟
|
|
|
- decision.action = FrameAction::DELAY;
|
|
|
- decision.delay = std::min(delay + diff, 0.5); // 最大延迟500ms
|
|
|
- decision.reason = "Video severely ahead, large delay";
|
|
|
- } else {
|
|
|
- // 其他情况,使用默认延迟
|
|
|
- decision.action = FrameAction::DISPLAY;
|
|
|
- decision.delay = delay;
|
|
|
- decision.reason = "Sync error large, default display";
|
|
|
- }
|
|
|
-
|
|
|
- // 触发恢复机制
|
|
|
- if (state_ != SyncState::RECOVERING && recoveryAttempts_ < config_.maxRecoveryAttempts) {
|
|
|
- state_ = SyncState::RECOVERING;
|
|
|
- recoveryAttempts_++;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 更新统计
|
|
|
- {
|
|
|
- std::lock_guard<std::mutex> lock(statsMutex_);
|
|
|
- stats_.totalFrames++;
|
|
|
- stats_.syncError = diff;
|
|
|
-
|
|
|
- // 更新平均同步误差
|
|
|
- if (stats_.totalFrames == 1) {
|
|
|
- stats_.avgSyncError = std::abs(diff);
|
|
|
- } else {
|
|
|
- stats_.avgSyncError = stats_.avgSyncError * 0.9 + std::abs(diff) * 0.1;
|
|
|
- }
|
|
|
-
|
|
|
- // 更新最大同步误差
|
|
|
- stats_.maxSyncError = std::max(stats_.maxSyncError, std::abs(diff));
|
|
|
- }
|
|
|
-
|
|
|
- return decision;
|
|
|
-}
|
|
|
-
|
|
|
-FrameDecision SynchronizerV2::shouldPlayAudioFrame(int64_t pts, double timeBase, double duration) {
|
|
|
- FrameDecision decision;
|
|
|
- decision.actualPts = pts;
|
|
|
-
|
|
|
- if (!running_ || paused_) {
|
|
|
- decision.action = FrameAction::DELAY;
|
|
|
- decision.delay = 0.01; // 10ms
|
|
|
- decision.reason = paused_ ? "Paused" : "Not running";
|
|
|
- return decision;
|
|
|
- }
|
|
|
-
|
|
|
- // 参考AVPlayer2的音频帧播放决策算法
|
|
|
- double delay = duration > 0 ? duration : 0.02; // 默认20ms
|
|
|
-
|
|
|
- // 如果音频是主时钟,直接播放
|
|
|
- if (masterClockType_ == ClockType::AUDIO) {
|
|
|
- decision.action = FrameAction::DISPLAY;
|
|
|
- decision.delay = delay;
|
|
|
- decision.reason = "Audio master";
|
|
|
- decision.targetPts = pts;
|
|
|
- return decision;
|
|
|
- }
|
|
|
-
|
|
|
- // 获取主时钟并计算同步误差
|
|
|
- int64_t masterClock = getMasterClock(false); // 不使用预测,获取当前值
|
|
|
- decision.targetPts = masterClock;
|
|
|
-
|
|
|
- // 检查主时钟是否有效
|
|
|
- if (masterClock == AV_NOPTS_VALUE) {
|
|
|
- decision.action = FrameAction::DISPLAY;
|
|
|
- decision.delay = delay;
|
|
|
- decision.reason = "Master clock invalid, force play";
|
|
|
- return decision;
|
|
|
- }
|
|
|
-
|
|
|
- double audioPts = ptsToSeconds(pts, timeBase);
|
|
|
- double masterPts = ptsToSeconds(masterClock, timeBase);
|
|
|
- double diff = audioPts - masterPts;
|
|
|
- decision.syncError = diff;
|
|
|
-
|
|
|
- // 参考packets_sync.cpp的AV_NOSYNC_THRESHOLD检查
|
|
|
- if (std::isnan(diff) || std::isinf(diff) || std::abs(diff) >= config_.noSyncThreshold) {
|
|
|
- // 同步误差过大,不进行同步修正,直接播放
|
|
|
- decision.action = FrameAction::DISPLAY;
|
|
|
- decision.delay = delay;
|
|
|
- decision.reason = "Sync error too large (>" + std::to_string(config_.noSyncThreshold) + "s), no sync";
|
|
|
-
|
|
|
- // 记录大误差日志
|
|
|
- if (std::abs(diff) > 1.0) {
|
|
|
- Logger::instance().warning("Large audio sync error: audioPTS=" +
|
|
|
- std::to_string(audioPts) + "s, masterPTS=" +
|
|
|
- std::to_string(masterPts) + "s, diff=" +
|
|
|
- std::to_string(diff) + "s");
|
|
|
- }
|
|
|
-
|
|
|
- return decision;
|
|
|
- }
|
|
|
-
|
|
|
- // 参考packets_sync.cpp的音频同步算法
|
|
|
- double sync_threshold = config_.syncThreshold;
|
|
|
-
|
|
|
- // 正常同步处理
|
|
|
- if (diff <= -sync_threshold) {
|
|
|
- // 音频落后太多,丢帧追赶
|
|
|
- decision.action = FrameAction::DROP;
|
|
|
- decision.reason = "Audio too slow, drop frame (diff=" + std::to_string(diff * 1000) + "ms)";
|
|
|
-
|
|
|
- // 通知丢帧
|
|
|
- if (frameDropCallback_) {
|
|
|
- frameDropCallback_(ClockType::AUDIO, pts);
|
|
|
- }
|
|
|
-
|
|
|
- // 更新统计
|
|
|
- std::lock_guard<std::mutex> lock(statsMutex_);
|
|
|
- stats_.droppedFrames++;
|
|
|
-
|
|
|
- } else if (diff >= sync_threshold) {
|
|
|
- // 音频超前,延迟播放
|
|
|
- decision.action = FrameAction::DELAY;
|
|
|
- decision.delay = delay + diff;
|
|
|
- decision.reason = "Audio too fast, delay (diff=" + std::to_string(diff * 1000) + "ms)";
|
|
|
-
|
|
|
- } else {
|
|
|
- // 正常播放
|
|
|
- decision.action = FrameAction::DISPLAY;
|
|
|
- decision.delay = delay;
|
|
|
- decision.reason = "Normal play (diff=" + std::to_string(diff * 1000) + "ms)";
|
|
|
- }
|
|
|
-
|
|
|
- // 更新统计
|
|
|
- {
|
|
|
- std::lock_guard<std::mutex> lock(statsMutex_);
|
|
|
- stats_.totalFrames++;
|
|
|
- stats_.syncError = diff;
|
|
|
-
|
|
|
- // 更新平均同步误差
|
|
|
- if (stats_.totalFrames == 1) {
|
|
|
- stats_.avgSyncError = std::abs(diff);
|
|
|
- } else {
|
|
|
- stats_.avgSyncError = stats_.avgSyncError * 0.9 + std::abs(diff) * 0.1;
|
|
|
- }
|
|
|
-
|
|
|
- // 更新最大同步误差
|
|
|
- stats_.maxSyncError = std::max(stats_.maxSyncError, std::abs(diff));
|
|
|
- }
|
|
|
-
|
|
|
- return decision;
|
|
|
-}
|
|
|
-
|
|
|
-double SynchronizerV2::calculateTargetDelay(int64_t pts, double timeBase, ClockType clockType) {
|
|
|
- if (!running_) {
|
|
|
- return 0.0;
|
|
|
- }
|
|
|
-
|
|
|
- // 参考packets_sync.cpp的compute_target_delay算法
|
|
|
- double delay = 0.0;
|
|
|
-
|
|
|
- // 基础帧延迟
|
|
|
- if (clockType == ClockType::VIDEO) {
|
|
|
- delay = 1.0 / 25.0; // 默认25fps,40ms
|
|
|
- } else {
|
|
|
- delay = 0.0; // 音频不需要基础延迟
|
|
|
- }
|
|
|
-
|
|
|
- // 如果不是视频主时钟模式,需要进行同步调整
|
|
|
- if (masterClockType_ != ClockType::VIDEO && clockType == ClockType::VIDEO) {
|
|
|
- // 获取主时钟
|
|
|
- int64_t masterClock = getMasterClock(true);
|
|
|
- if (masterClock == AV_NOPTS_VALUE) {
|
|
|
- return delay; // 主时钟无效,返回基础延迟
|
|
|
- }
|
|
|
-
|
|
|
- // 计算视频时钟与主时钟的差异
|
|
|
- double videoPts = ptsToSeconds(pts, timeBase);
|
|
|
- double masterPts = ptsToSeconds(masterClock, timeBase);
|
|
|
- double diff = videoPts - masterPts;
|
|
|
-
|
|
|
- // 参考packets_sync.cpp的AV_NOSYNC_THRESHOLD检查
|
|
|
- if (std::isnan(diff) || std::isinf(diff) || std::abs(diff) >= config_.noSyncThreshold) {
|
|
|
- // 同步误差过大,不进行同步校正,返回基础延迟
|
|
|
- return delay;
|
|
|
- }
|
|
|
-
|
|
|
- // 计算同步阈值,参考packets_sync.cpp的动态阈值算法
|
|
|
- double sync_threshold = std::max(config_.syncThreshold, std::min(0.1, delay));
|
|
|
-
|
|
|
- // 检查差异是否在合理范围内(避免异常值)
|
|
|
- if (!std::isnan(diff) && std::abs(diff) < config_.maxSyncError) {
|
|
|
- if (diff <= -sync_threshold) {
|
|
|
- // 视频落后,减少延迟以追赶
|
|
|
- delay = std::max(0.0, delay + diff);
|
|
|
- } else if (diff >= sync_threshold && delay > config_.frameDupThreshold) {
|
|
|
- // 视频超前且延迟足够大,增加延迟
|
|
|
- delay = delay + diff;
|
|
|
- } else if (diff >= sync_threshold) {
|
|
|
- // 视频超前但延迟较小,加倍延迟
|
|
|
- delay = 2 * delay;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return delay;
|
|
|
-}
|
|
|
-
|
|
|
-bool SynchronizerV2::shouldDropFrame(int64_t pts, double timeBase, ClockType clockType) {
|
|
|
- if (!running_ || clockType == masterClockType_) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- int64_t masterClock = getMasterClock();
|
|
|
- if (masterClock == AV_NOPTS_VALUE) {
|
|
|
- return false; // 主时钟无效,不丢帧
|
|
|
- }
|
|
|
-
|
|
|
- double ptsInSeconds = ptsToSeconds(pts, timeBase);
|
|
|
- double masterClockInSeconds = ptsToSeconds(masterClock, timeBase);
|
|
|
- double diff = ptsInSeconds - masterClockInSeconds;
|
|
|
-
|
|
|
- // 参考packets_sync.cpp的AV_NOSYNC_THRESHOLD检查
|
|
|
- if (std::isnan(diff) || std::isinf(diff) || std::abs(diff) >= config_.noSyncThreshold) {
|
|
|
- return false; // 同步误差过大,不丢帧
|
|
|
- }
|
|
|
-
|
|
|
- return diff < -config_.frameDropThreshold;
|
|
|
-}
|
|
|
-
|
|
|
-bool SynchronizerV2::shouldDuplicateFrame(int64_t pts, double timeBase, ClockType clockType) {
|
|
|
- if (!running_ || clockType == masterClockType_) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- int64_t masterClock = getMasterClock();
|
|
|
- if (masterClock == AV_NOPTS_VALUE) {
|
|
|
- return false; // 主时钟无效,不复制帧
|
|
|
- }
|
|
|
-
|
|
|
- double ptsInSeconds = ptsToSeconds(pts, timeBase);
|
|
|
- double masterClockInSeconds = ptsToSeconds(masterClock, timeBase);
|
|
|
- double diff = ptsInSeconds - masterClockInSeconds;
|
|
|
-
|
|
|
- // 参考packets_sync.cpp的AV_NOSYNC_THRESHOLD检查
|
|
|
- if (std::isnan(diff) || std::isinf(diff) || std::abs(diff) >= config_.noSyncThreshold) {
|
|
|
- return false; // 同步误差过大,不复制帧
|
|
|
- }
|
|
|
-
|
|
|
- return diff > config_.frameDupThreshold;
|
|
|
-}
|
|
|
-
|
|
|
-double SynchronizerV2::calculateSyncError() const {
|
|
|
- if (!running_) {
|
|
|
- return 0.0;
|
|
|
- }
|
|
|
-
|
|
|
- double audioClock = getAudioClock();
|
|
|
- double videoClock = getVideoClock();
|
|
|
-
|
|
|
- if (audioClock <= 0 || videoClock <= 0) {
|
|
|
- return 0.0;
|
|
|
- }
|
|
|
-
|
|
|
- return std::abs(audioClock - videoClock);
|
|
|
-}
|
|
|
-
|
|
|
-// 内部版本,假设调用者已经持有clockMutex_锁
|
|
|
-double SynchronizerV2::calculateSyncErrorInternal() const {
|
|
|
- if (!running_) {
|
|
|
- return 0.0;
|
|
|
- }
|
|
|
-
|
|
|
- // 直接计算时钟值,避免调用getClock导致死锁,使用packets_sync.cpp的算法
|
|
|
- double audioClock = 0.0;
|
|
|
- double videoClock = 0.0;
|
|
|
- double currentTime = getSystemTime();
|
|
|
-
|
|
|
- // 计算音频时钟,使用packets_sync.cpp的get_clock算法
|
|
|
- if (!std::isnan(audioClock_.pts)) {
|
|
|
- if (audioClock_.paused) {
|
|
|
- audioClock = audioClock_.pts;
|
|
|
- } else {
|
|
|
- // 使用packets_sync.cpp的算法:pts + pts_drift + (current_time - last_updated) * speed
|
|
|
- audioClock = audioClock_.pts + audioClock_.pts_drift + (currentTime - audioClock_.lastUpdate) * audioClock_.speed;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 计算视频时钟,使用packets_sync.cpp的get_clock算法
|
|
|
- if (!std::isnan(videoClock_.pts)) {
|
|
|
- if (videoClock_.paused) {
|
|
|
- videoClock = videoClock_.pts;
|
|
|
- } else {
|
|
|
- // 使用packets_sync.cpp的算法:pts + pts_drift + (current_time - last_updated) * speed
|
|
|
- videoClock = videoClock_.pts + videoClock_.pts_drift + (currentTime - videoClock_.lastUpdate) * videoClock_.speed;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (audioClock <= 0 || videoClock <= 0) {
|
|
|
- return 0.0;
|
|
|
- }
|
|
|
-
|
|
|
- return std::abs(audioClock - videoClock);
|
|
|
-}
|
|
|
-
|
|
|
-double SynchronizerV2::calculateAudioDelay(int64_t pts, double timeBase) const {
|
|
|
- if (masterClockType_ == ClockType::AUDIO) {
|
|
|
- return 0.0;
|
|
|
- }
|
|
|
-
|
|
|
- int64_t masterClock = getMasterClock();
|
|
|
- double ptsInSeconds = ptsToSeconds(pts, timeBase);
|
|
|
- double masterClockInSeconds = ptsToSeconds(masterClock, timeBase);
|
|
|
- return ptsInSeconds - masterClockInSeconds;
|
|
|
-}
|
|
|
-
|
|
|
-double SynchronizerV2::calculateVideoDelay(int64_t pts, double timeBase) const {
|
|
|
- if (masterClockType_ == ClockType::VIDEO) {
|
|
|
- return 0.0;
|
|
|
- }
|
|
|
-
|
|
|
- int64_t masterClock = getMasterClock();
|
|
|
- double ptsInSeconds = ptsToSeconds(pts, timeBase);
|
|
|
- double masterClockInSeconds = ptsToSeconds(masterClock, timeBase);
|
|
|
- return ptsInSeconds - masterClockInSeconds;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setConfig(const SyncConfigV2& config) {
|
|
|
- std::lock_guard<std::mutex> lock(configMutex_);
|
|
|
- config_ = config;
|
|
|
-
|
|
|
- // 重新选择主时钟
|
|
|
- selectMasterClock();
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 config updated");
|
|
|
-}
|
|
|
-
|
|
|
-SyncConfigV2 SynchronizerV2::getConfig() const {
|
|
|
- std::lock_guard<std::mutex> lock(configMutex_);
|
|
|
- return config_;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setSyncStrategy(SyncStrategy strategy) {
|
|
|
- std::lock_guard<std::mutex> lock(configMutex_);
|
|
|
- config_.strategy = strategy;
|
|
|
- selectMasterClock();
|
|
|
-
|
|
|
- Logger::instance().info("Sync strategy set to: " + std::to_string(static_cast<int>(strategy)));
|
|
|
-}
|
|
|
-
|
|
|
-SyncStrategy SynchronizerV2::getSyncStrategy() const {
|
|
|
- std::lock_guard<std::mutex> lock(configMutex_);
|
|
|
- return config_.strategy;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setPlaybackSpeed(double speed) {
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
-
|
|
|
- audioClock_.speed = speed;
|
|
|
- videoClock_.speed = speed;
|
|
|
- externalClock_.speed = speed;
|
|
|
-
|
|
|
- Logger::instance().info("Playback speed set to: " + std::to_string(speed) + "x");
|
|
|
-}
|
|
|
-
|
|
|
-double SynchronizerV2::getPlaybackSpeed() const {
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
- return audioClock_.speed;
|
|
|
-}
|
|
|
-
|
|
|
-bool SynchronizerV2::isSynchronized() const {
|
|
|
- return state_ == SyncState::SYNCHRONIZED;
|
|
|
-}
|
|
|
-
|
|
|
-SyncStatsV2 SynchronizerV2::getStats() const {
|
|
|
- std::lock_guard<std::mutex> lock(statsMutex_);
|
|
|
- SyncStatsV2 stats = stats_;
|
|
|
-
|
|
|
- // 更新当前时钟值
|
|
|
- stats.audioClock = getAudioClock();
|
|
|
- stats.videoClock = getVideoClock();
|
|
|
- stats.externalClock = getExternalClock();
|
|
|
- stats.masterClock = getMasterClock();
|
|
|
- stats.state = state_;
|
|
|
- stats.masterClockType = masterClockType_;
|
|
|
-
|
|
|
- return stats;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::resetStats() {
|
|
|
- std::lock_guard<std::mutex> lock(statsMutex_);
|
|
|
- stats_ = SyncStatsV2();
|
|
|
- stats_.lastUpdateTime = std::chrono::steady_clock::now();
|
|
|
-
|
|
|
- Logger::instance().info("SynchronizerV2 stats reset");
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setSyncEventCallback(SyncEventCallback callback) {
|
|
|
- syncEventCallback_ = callback;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setFrameDropCallback(FrameDropCallback callback) {
|
|
|
- frameDropCallback_ = callback;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setFrameDuplicateCallback(FrameDuplicateCallback callback) {
|
|
|
- frameDuplicateCallback_ = callback;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setSyncErrorCallback(SyncErrorCallback callback) {
|
|
|
- syncErrorCallback_ = callback;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::enableAdaptiveSync(bool enable) {
|
|
|
- std::lock_guard<std::mutex> lock(configMutex_);
|
|
|
- config_.enableAdaptiveSync = enable;
|
|
|
-
|
|
|
- Logger::instance().info("Adaptive sync " + std::string(enable ? "enabled" : "disabled"));
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::enablePrediction(bool enable) {
|
|
|
- std::lock_guard<std::mutex> lock(configMutex_);
|
|
|
- config_.enablePrediction = enable;
|
|
|
-
|
|
|
- Logger::instance().info("Prediction " + std::string(enable ? "enabled" : "disabled"));
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setClockUpdateInterval(double interval) {
|
|
|
- std::lock_guard<std::mutex> lock(configMutex_);
|
|
|
- config_.clockUpdateInterval = interval;
|
|
|
-
|
|
|
- Logger::instance().info("Clock update interval set to: " + std::to_string(interval * 1000) + "ms");
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::setSmoothingWindow(int window) {
|
|
|
- std::lock_guard<std::mutex> lock(configMutex_);
|
|
|
- config_.smoothingWindow = window;
|
|
|
-
|
|
|
- // 调整历史记录大小
|
|
|
- std::lock_guard<std::mutex> historyLock(historyMutex_);
|
|
|
- while (audioClockHistory_.size() > static_cast<size_t>(window)) {
|
|
|
- audioClockHistory_.pop_front();
|
|
|
- }
|
|
|
- while (videoClockHistory_.size() > static_cast<size_t>(window)) {
|
|
|
- videoClockHistory_.pop_front();
|
|
|
- }
|
|
|
- while (syncErrorHistory_.size() > static_cast<size_t>(window)) {
|
|
|
- syncErrorHistory_.pop_front();
|
|
|
- }
|
|
|
-
|
|
|
- Logger::instance().info("Smoothing window set to: " + std::to_string(window));
|
|
|
-}
|
|
|
-
|
|
|
-std::string SynchronizerV2::getDebugInfo() const {
|
|
|
- std::ostringstream oss;
|
|
|
-
|
|
|
- SyncStatsV2 stats = getStats();
|
|
|
-
|
|
|
- oss << std::fixed << std::setprecision(3);
|
|
|
- oss << "SynchronizerV2 Debug Info:\n";
|
|
|
- oss << " State: " << static_cast<int>(stats.state) << "\n";
|
|
|
- oss << " Master Clock: " << static_cast<int>(stats.masterClockType) << "\n";
|
|
|
- oss << " Audio Clock: " << stats.audioClock << "s\n";
|
|
|
- oss << " Video Clock: " << stats.videoClock << "s\n";
|
|
|
- oss << " External Clock: " << stats.externalClock << "s\n";
|
|
|
- oss << " Master Clock: " << stats.masterClock << "s\n";
|
|
|
- oss << " Sync Error: " << stats.syncError * 1000 << "ms\n";
|
|
|
- oss << " Avg Sync Error: " << stats.avgSyncError * 1000 << "ms\n";
|
|
|
- oss << " Max Sync Error: " << stats.maxSyncError * 1000 << "ms\n";
|
|
|
- oss << " Total Frames: " << stats.totalFrames << "\n";
|
|
|
- oss << " Dropped Frames: " << stats.droppedFrames << "\n";
|
|
|
- oss << " Duplicated Frames: " << stats.duplicatedFrames << "\n";
|
|
|
- oss << " Running: " << (running_ ? "Yes" : "No") << "\n";
|
|
|
- oss << " Paused: " << (paused_ ? "Yes" : "No") << "\n";
|
|
|
-
|
|
|
- return oss.str();
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::dumpClockInfo() const {
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
-
|
|
|
- Logger::instance().info("Clock Info Dump:");
|
|
|
- Logger::instance().info(" Audio - PTS: " + std::to_string(audioClock_.pts) +
|
|
|
- ", Speed: " + std::to_string(audioClock_.speed) +
|
|
|
- ", Paused: " + (audioClock_.paused ? "Yes" : "No"));
|
|
|
- Logger::instance().info(" Video - PTS: " + std::to_string(videoClock_.pts) +
|
|
|
- ", Speed: " + std::to_string(videoClock_.speed) +
|
|
|
- ", Paused: " + (videoClock_.paused ? "Yes" : "No"));
|
|
|
- Logger::instance().info(" External - PTS: " + std::to_string(externalClock_.pts) +
|
|
|
- ", Speed: " + std::to_string(externalClock_.speed) +
|
|
|
- ", Paused: " + (externalClock_.paused ? "Yes" : "No"));
|
|
|
-}
|
|
|
-
|
|
|
-// 私有方法实现
|
|
|
-
|
|
|
-ErrorCode SynchronizerV2::updateClock(ClockType type, int64_t pts, double timeBase, int serial) {
|
|
|
- if (!initialized_) {
|
|
|
- return ErrorCode::NOT_INITIALIZED;
|
|
|
- }
|
|
|
-
|
|
|
- // 参考packets_sync.cpp的set_clock_at实现,确保与AVPlayer2一致
|
|
|
- double currentTime = getSystemTime();
|
|
|
- double ptsInSeconds = ptsToSeconds(pts, timeBase);
|
|
|
-
|
|
|
- // 在锁内更新时钟数据
|
|
|
- {
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
-
|
|
|
- ClockInfo* clock = nullptr;
|
|
|
- switch (type) {
|
|
|
- case ClockType::AUDIO:
|
|
|
- clock = &audioClock_;
|
|
|
- break;
|
|
|
- case ClockType::VIDEO:
|
|
|
- clock = &videoClock_;
|
|
|
- break;
|
|
|
- case ClockType::EXTERNAL:
|
|
|
- clock = &externalClock_;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return ErrorCode::INVALID_PARAMS;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查序列号,参考packets_sync.cpp的序列号检查机制
|
|
|
- if (serial != 0 && clock->serial != serial) {
|
|
|
- // 序列号不匹配,可能是seek操作,重置时钟
|
|
|
- resetClock(type);
|
|
|
- clock->serial = serial;
|
|
|
- }
|
|
|
-
|
|
|
- // 严格按照packets_sync.cpp的set_clock_at算法更新时钟
|
|
|
- if (pts != AV_NOPTS_VALUE) {
|
|
|
- // 参考packets_sync.cpp: clock->pts_drift = pts - time
|
|
|
- clock->pts_drift = ptsInSeconds - currentTime;
|
|
|
- clock->pts = ptsInSeconds; // 存储转换后的秒值,与packets_sync.cpp一致
|
|
|
- clock->lastUpdate = currentTime;
|
|
|
- } else {
|
|
|
- clock->pts = std::numeric_limits<double>::quiet_NaN();
|
|
|
- clock->pts_drift = 0.0;
|
|
|
- clock->lastUpdate = currentTime;
|
|
|
- }
|
|
|
-
|
|
|
- clock->time = currentTime;
|
|
|
- clock->serial = serial;
|
|
|
-
|
|
|
- // 添加调试日志
|
|
|
- static int logCounter = 0;
|
|
|
- if (++logCounter % 100 == 0) { // 每100次更新记录一次
|
|
|
- std::string clockName = (type == ClockType::AUDIO) ? "Audio" :
|
|
|
- (type == ClockType::VIDEO) ? "Video" : "External";
|
|
|
- Logger::instance().info("Clock Update [" + clockName + "]: PTS=" +
|
|
|
- std::to_string(pts) + ", PTSSeconds=" +
|
|
|
- std::to_string(ptsInSeconds) + ", SystemTime=" +
|
|
|
- std::to_string(currentTime) + ", Drift=" +
|
|
|
- std::to_string(clock->drift));
|
|
|
- }
|
|
|
-
|
|
|
- // 平滑处理(保持原有逻辑,但确保使用正确的PTS值)
|
|
|
- if (config_.smoothingWindow > 1) {
|
|
|
- clock->smoothedPts = smoothClock(type, static_cast<int64_t>(ptsInSeconds * AV_TIME_BASE));
|
|
|
- } else {
|
|
|
- clock->smoothedPts = static_cast<int64_t>(ptsInSeconds * AV_TIME_BASE);
|
|
|
- }
|
|
|
-
|
|
|
- // 更新历史记录(转换为AV_TIME_BASE格式)
|
|
|
- updateClockHistory(type, static_cast<int64_t>(ptsInSeconds * AV_TIME_BASE));
|
|
|
-
|
|
|
- // 如果这是主时钟,同步外部时钟到主时钟
|
|
|
- if (type == masterClockType_ && type != ClockType::EXTERNAL) {
|
|
|
- syncClockToSlave(&externalClock_, clock);
|
|
|
- }
|
|
|
-
|
|
|
- // 定期更新统计信息
|
|
|
- auto now = std::chrono::steady_clock::now();
|
|
|
- if (std::chrono::duration_cast<std::chrono::milliseconds>(now - lastStatsUpdate_).count() > 100) {
|
|
|
- updateStats();
|
|
|
- lastStatsUpdate_ = now;
|
|
|
- }
|
|
|
- } // 释放clockMutex_锁
|
|
|
-
|
|
|
- // 在锁外更新同步状态,避免死锁
|
|
|
- updateSyncState();
|
|
|
-
|
|
|
- return ErrorCode::SUCCESS;
|
|
|
-}
|
|
|
-
|
|
|
-int64_t SynchronizerV2::getClock(ClockType type, bool predict) const {
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
-
|
|
|
- const ClockInfo* clock = nullptr;
|
|
|
- switch (type) {
|
|
|
- case ClockType::AUDIO:
|
|
|
- clock = &audioClock_;
|
|
|
- break;
|
|
|
- case ClockType::VIDEO:
|
|
|
- clock = &videoClock_;
|
|
|
- break;
|
|
|
- case ClockType::EXTERNAL:
|
|
|
- clock = &externalClock_;
|
|
|
- break;
|
|
|
- case ClockType::SYSTEM:
|
|
|
- return static_cast<int64_t>(getSystemTime() * AV_TIME_BASE);
|
|
|
- default:
|
|
|
- return AV_NOPTS_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- // 严格按照packets_sync.cpp的get_clock实现
|
|
|
- // 检查时钟是否有效(pts不为NAN,与packets_sync.cpp一致)
|
|
|
- if (std::isnan(clock->pts)) {
|
|
|
- return AV_NOPTS_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- double clockValue;
|
|
|
- if (clock->paused) {
|
|
|
- // 暂停状态下,直接返回暂停时的PTS值
|
|
|
- clockValue = clock->pts;
|
|
|
- } else {
|
|
|
- // 运行状态下,使用packets_sync.cpp的get_clock算法
|
|
|
- // get_clock算法:pts_drift + time - (time - last_updated) * (1.0 - speed)
|
|
|
- // 等价于:pts + pts_drift + (current_time - last_updated) * speed
|
|
|
- double currentTime = av_gettime_relative() / 1000000.0;
|
|
|
- clockValue = clock->pts_drift + currentTime - (currentTime - clock->lastUpdate) * (1.0 - clock->speed);
|
|
|
- }
|
|
|
-
|
|
|
- // 转换为AV_TIME_BASE时间基准
|
|
|
- int64_t currentPts = static_cast<int64_t>(clockValue * AV_TIME_BASE);
|
|
|
-
|
|
|
- // 如果启用预测
|
|
|
- if (predict && config_.enablePrediction) {
|
|
|
- return predictClock(type, config_.predictionWindow);
|
|
|
- }
|
|
|
-
|
|
|
- return currentPts;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::resetClock(ClockType type) {
|
|
|
- ClockInfo* clock = nullptr;
|
|
|
- switch (type) {
|
|
|
- case ClockType::AUDIO:
|
|
|
- clock = &audioClock_;
|
|
|
- break;
|
|
|
- case ClockType::VIDEO:
|
|
|
- clock = &videoClock_;
|
|
|
- break;
|
|
|
- case ClockType::EXTERNAL:
|
|
|
- clock = &externalClock_;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 严格按照packets_sync.cpp的init_clock实现
|
|
|
- // init_clock调用set_clock(c, NAN, -1),而set_clock使用av_gettime_relative
|
|
|
- double currentTime = av_gettime_relative() / 1000000.0;
|
|
|
-
|
|
|
- // 统一初始化所有时钟,与packets_sync.cpp保持一致
|
|
|
- clock->speed = 1.0;
|
|
|
- clock->paused = false;
|
|
|
-
|
|
|
- // 调用set_clock(c, NAN, -1)的等价操作
|
|
|
- clock->pts = std::numeric_limits<double>::quiet_NaN(); // 使用NAN,与packets_sync.cpp一致
|
|
|
- clock->pts_drift = clock->pts - currentTime; // set_clock_at的逻辑
|
|
|
- clock->lastUpdate = currentTime;
|
|
|
- clock->serial = -1;
|
|
|
-
|
|
|
- // 保留SynchronizerV2特有的字段
|
|
|
- clock->time = currentTime;
|
|
|
- clock->drift = 0.0;
|
|
|
- clock->smoothedPts = AV_NOPTS_VALUE;
|
|
|
-}
|
|
|
-
|
|
|
-// 严格按照packets_sync.cpp的sync_clock_to_slave实现
|
|
|
-void SynchronizerV2::syncClockToSlave(ClockInfo* slave, const ClockInfo* master) {
|
|
|
- if (!slave || !master) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- double currentTime = getSystemTime();
|
|
|
-
|
|
|
- // 计算主时钟当前值,使用packets_sync.cpp的get_clock算法
|
|
|
- double masterClock = std::numeric_limits<double>::quiet_NaN();
|
|
|
- if (!std::isnan(master->pts)) {
|
|
|
- if (master->paused) {
|
|
|
- masterClock = master->pts;
|
|
|
- } else {
|
|
|
- // 使用packets_sync.cpp的get_clock算法:pts_drift + time - (time - last_updated) * (1.0 - speed)
|
|
|
- masterClock = master->pts_drift + currentTime - (currentTime - master->lastUpdate) * (1.0 - master->speed);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 计算从时钟当前值,使用packets_sync.cpp的get_clock算法
|
|
|
- double slaveClock = std::numeric_limits<double>::quiet_NaN();
|
|
|
- if (!std::isnan(slave->pts)) {
|
|
|
- if (slave->paused) {
|
|
|
- slaveClock = slave->pts;
|
|
|
- } else {
|
|
|
- // 使用packets_sync.cpp的get_clock算法:pts_drift + time - (time - last_updated) * (1.0 - speed)
|
|
|
- slaveClock = slave->pts_drift + currentTime - (currentTime - slave->lastUpdate) * (1.0 - slave->speed);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 参考packets_sync.cpp的sync_clock_to_slave逻辑
|
|
|
- if (!std::isnan(masterClock) &&
|
|
|
- (std::isnan(slaveClock) || std::abs(masterClock - slaveClock) > config_.noSyncThreshold)) {
|
|
|
- // 按照packets_sync.cpp的set_clock_at算法同步从时钟到主时钟
|
|
|
- slave->pts = masterClock;
|
|
|
- slave->pts_drift = masterClock - currentTime;
|
|
|
- slave->lastUpdate = currentTime;
|
|
|
- slave->serial = master->serial;
|
|
|
-
|
|
|
- // 保留SynchronizerV2特有的字段
|
|
|
- slave->time = currentTime;
|
|
|
- slave->drift = masterClock - currentTime;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::pauseClock(ClockType type, bool pause) {
|
|
|
- ClockInfo* clock = nullptr;
|
|
|
- switch (type) {
|
|
|
- case ClockType::AUDIO:
|
|
|
- clock = &audioClock_;
|
|
|
- break;
|
|
|
- case ClockType::VIDEO:
|
|
|
- clock = &videoClock_;
|
|
|
- break;
|
|
|
- case ClockType::EXTERNAL:
|
|
|
- clock = &externalClock_;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (clock->paused != pause) {
|
|
|
- double currentTime = getSystemTime();
|
|
|
-
|
|
|
- if (pause) {
|
|
|
- // 暂停时保存当前PTS,使用packets_sync.cpp的get_clock算法计算当前值
|
|
|
- if (!clock->paused && !std::isnan(clock->pts)) {
|
|
|
- clock->pts = clock->pts_drift + currentTime - (currentTime - clock->lastUpdate) * (1.0 - clock->speed);
|
|
|
- clock->pts_drift = 0.0; // 暂停后drift重置为0
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 恢复时重新设置pts_drift,参考packets_sync.cpp的set_clock_at
|
|
|
- if (!std::isnan(clock->pts)) {
|
|
|
- clock->pts_drift = clock->pts - currentTime;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- clock->paused = pause;
|
|
|
- clock->lastUpdate = currentTime;
|
|
|
- clock->time = currentTime; // 保留SynchronizerV2特有字段
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::selectMasterClock() {
|
|
|
- ClockType newMasterClock = masterClockType_;
|
|
|
-
|
|
|
- switch (config_.strategy) {
|
|
|
- case SyncStrategy::AUDIO_MASTER:
|
|
|
- newMasterClock = ClockType::AUDIO;
|
|
|
- break;
|
|
|
-
|
|
|
- case SyncStrategy::VIDEO_MASTER:
|
|
|
- newMasterClock = ClockType::VIDEO;
|
|
|
- break;
|
|
|
-
|
|
|
- case SyncStrategy::EXTERNAL_MASTER:
|
|
|
- newMasterClock = ClockType::EXTERNAL;
|
|
|
- break;
|
|
|
-
|
|
|
- case SyncStrategy::ADAPTIVE: {
|
|
|
- // 参考AVPlayer2的自适应主时钟选择算法
|
|
|
- if (config_.enableAdaptiveSync) {
|
|
|
- bool hasAudio = (hasAudioStream_ && !std::isnan(audioClock_.pts) && !audioClock_.paused);
|
|
|
- bool hasVideo = (hasVideoStream_ && !std::isnan(videoClock_.pts) && !videoClock_.paused);
|
|
|
-
|
|
|
- if (hasAudio && hasVideo) {
|
|
|
- // 音视频都存在时,评估时钟质量
|
|
|
- double currentTime = getSystemTime();
|
|
|
-
|
|
|
- // 计算音频时钟的稳定性
|
|
|
- double audioStability = 1.0;
|
|
|
- if (audioClock_.time > 0) {
|
|
|
- double audioAge = currentTime - audioClock_.time;
|
|
|
- audioStability = std::exp(-audioAge / 2.0); // 2秒衰减
|
|
|
- }
|
|
|
-
|
|
|
- // 计算视频时钟的稳定性
|
|
|
- double videoStability = 1.0;
|
|
|
- if (videoClock_.time > 0) {
|
|
|
- double videoAge = currentTime - videoClock_.time;
|
|
|
- videoStability = std::exp(-videoAge / 2.0); // 2秒衰减
|
|
|
- }
|
|
|
-
|
|
|
- // 考虑时钟漂移
|
|
|
- double audioDrift = std::abs(audioClock_.drift);
|
|
|
- double videoDrift = std::abs(videoClock_.drift);
|
|
|
-
|
|
|
- // 音频时钟通常更稳定,给予优先权
|
|
|
- double audioScore = audioStability * 1.2 / (1.0 + audioDrift * 10.0);
|
|
|
- double videoScore = videoStability / (1.0 + videoDrift * 10.0);
|
|
|
-
|
|
|
- if (audioScore > videoScore && audioScore > 0.3) {
|
|
|
- newMasterClock = ClockType::AUDIO;
|
|
|
- } else if (videoScore > 0.3) {
|
|
|
- newMasterClock = ClockType::VIDEO;
|
|
|
- } else {
|
|
|
- newMasterClock = ClockType::EXTERNAL;
|
|
|
- }
|
|
|
- } else if (hasAudio) {
|
|
|
- // 只有音频
|
|
|
- newMasterClock = ClockType::AUDIO;
|
|
|
- } else if (hasVideo) {
|
|
|
- // 只有视频
|
|
|
- newMasterClock = ClockType::VIDEO;
|
|
|
- } else {
|
|
|
- // 都没有,使用外部时钟
|
|
|
- newMasterClock = ClockType::EXTERNAL;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 简单逻辑:优先音频,但要检查时钟有效性
|
|
|
- bool hasValidAudio = (hasAudioStream_ && !std::isnan(audioClock_.pts));
|
|
|
- bool hasValidVideo = (hasVideoStream_ && !std::isnan(videoClock_.pts));
|
|
|
-
|
|
|
- if (hasValidAudio) {
|
|
|
- newMasterClock = ClockType::AUDIO;
|
|
|
- } else if (hasValidVideo) {
|
|
|
- newMasterClock = ClockType::VIDEO;
|
|
|
- } else {
|
|
|
- // 音视频时钟都无效,使用外部时钟
|
|
|
- newMasterClock = ClockType::EXTERNAL;
|
|
|
- }
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 如果选择外部时钟作为主时钟,但外部时钟无效,则初始化它
|
|
|
- if (newMasterClock == ClockType::EXTERNAL && std::isnan(externalClock_.pts)) {
|
|
|
- double currentTime = av_gettime_relative() / 1000000.0;
|
|
|
- externalClock_.pts = currentTime;
|
|
|
- externalClock_.pts_drift = 0.0;
|
|
|
- externalClock_.lastUpdate = currentTime;
|
|
|
- externalClock_.time = currentTime;
|
|
|
- externalClock_.serial = 0;
|
|
|
- externalClock_.paused = false;
|
|
|
- externalClock_.speed = 1.0;
|
|
|
- externalClock_.drift = 0.0;
|
|
|
-
|
|
|
- Logger::instance().info("External clock initialized as master with current time: " + std::to_string(currentTime));
|
|
|
- }
|
|
|
-
|
|
|
- // 只有当主时钟真正改变时才更新和记录日志
|
|
|
- if (newMasterClock != masterClockType_) {
|
|
|
- ClockType oldMasterClock = masterClockType_;
|
|
|
- masterClockType_ = newMasterClock;
|
|
|
-
|
|
|
- // 获取时钟状态信息用于调试
|
|
|
- std::string audioStatus = "invalid";
|
|
|
- std::string videoStatus = "invalid";
|
|
|
- std::string externalStatus = "invalid";
|
|
|
-
|
|
|
- if (!std::isnan(audioClock_.pts)) {
|
|
|
- audioStatus = "valid(pts=" + std::to_string(audioClock_.pts) + ")";
|
|
|
- }
|
|
|
- if (!std::isnan(videoClock_.pts)) {
|
|
|
- videoStatus = "valid(pts=" + std::to_string(videoClock_.pts) + ")";
|
|
|
- }
|
|
|
- if (!std::isnan(externalClock_.pts)) {
|
|
|
- externalStatus = "valid(pts=" + std::to_string(externalClock_.pts) + ")";
|
|
|
- }
|
|
|
-
|
|
|
- Logger::instance().info("Master clock changed from "
|
|
|
- + std::to_string(static_cast<int>(oldMasterClock))
|
|
|
- + " to " + std::to_string(static_cast<int>(masterClockType_.load()))
|
|
|
- + " (hasAudio=" + std::to_string(hasAudioStream_.load())
|
|
|
- + ", hasVideo=" + std::to_string(hasVideoStream_.load())
|
|
|
- + ", audio=" + audioStatus
|
|
|
- + ", video=" + videoStatus
|
|
|
- + ", external=" + externalStatus + ")");
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::updateSyncState() {
|
|
|
- if (!running_) {
|
|
|
- state_ = SyncState::IDLE;
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (paused_) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- double syncError = calculateSyncErrorInternal();
|
|
|
-
|
|
|
- SyncState newState = state_;
|
|
|
- bool needRecovery = false;
|
|
|
-
|
|
|
- // 参考AVPlayer2的同步状态管理算法
|
|
|
- if (syncError <= config_.syncThreshold) {
|
|
|
- // 同步误差在可接受范围内
|
|
|
- if (state_ == SyncState::RECOVERING || state_ == SyncState::INITIALIZING) {
|
|
|
- // 从恢复或初始化状态转为同步状态
|
|
|
- newState = SyncState::SYNCHRONIZED;
|
|
|
- recoveryAttempts_ = 0;
|
|
|
- } else if (state_ != SyncState::SYNCHRONIZED) {
|
|
|
- newState = SyncState::SYNCHRONIZED;
|
|
|
- }
|
|
|
- } else if (syncError <= config_.adaptiveThreshold) {
|
|
|
- // 轻微漂移状态
|
|
|
- if (state_ == SyncState::SYNCHRONIZED) {
|
|
|
- newState = SyncState::DRIFT;
|
|
|
- } else if (state_ == SyncState::RECOVERING) {
|
|
|
- // 恢复中但误差仍较大,继续恢复
|
|
|
- double recoveryDuration = getCurrentTime() - recoveryStartTime_;
|
|
|
- if (recoveryDuration > 3.0) { // 3秒恢复超时
|
|
|
- if (recoveryAttempts_ < config_.maxRecoveryAttempts) {
|
|
|
- needRecovery = true;
|
|
|
- } else {
|
|
|
- newState = SyncState::ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } else if (syncError <= config_.maxSyncError) {
|
|
|
- // 同步误差较大但仍在可恢复范围内
|
|
|
- if (state_ != SyncState::RECOVERING) {
|
|
|
- newState = SyncState::ERROR;
|
|
|
- if (recoveryAttempts_ < config_.maxRecoveryAttempts) {
|
|
|
- needRecovery = true;
|
|
|
- newState = SyncState::RECOVERING;
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 已在恢复状态,检查恢复超时
|
|
|
- double recoveryDuration = getCurrentTime() - recoveryStartTime_;
|
|
|
- if (recoveryDuration > 5.0) { // 5秒恢复超时
|
|
|
- if (recoveryAttempts_ < config_.maxRecoveryAttempts) {
|
|
|
- needRecovery = true;
|
|
|
- } else {
|
|
|
- newState = SyncState::ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 同步误差过大
|
|
|
- newState = SyncState::ERROR;
|
|
|
- // 标记需要恢复,但不在这里直接调用attemptRecovery避免死锁
|
|
|
- if (recoveryAttempts_ < config_.maxRecoveryAttempts) {
|
|
|
- needRecovery = true;
|
|
|
- newState = SyncState::RECOVERING;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 检查长时间失同步的情况
|
|
|
- if (newState == SyncState::ERROR && recoveryAttempts_ >= config_.maxRecoveryAttempts) {
|
|
|
- static double lastResetTime = 0;
|
|
|
- double currentTime = getCurrentTime();
|
|
|
- if (currentTime - lastResetTime > 10.0) { // 10秒重置一次
|
|
|
- // 尝试重新初始化同步
|
|
|
- recoveryAttempts_ = 0;
|
|
|
- newState = SyncState::INITIALIZING;
|
|
|
- lastResetTime = currentTime;
|
|
|
- Logger::instance().warning("Sync error persists, attempting full reset");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (newState != state_) {
|
|
|
- SyncState oldState = state_;
|
|
|
- state_ = newState;
|
|
|
- notifyStateChange(newState);
|
|
|
-
|
|
|
- Logger::instance().info("Sync state changed from " + std::to_string(static_cast<int>(oldState)) +
|
|
|
- " to " + std::to_string(static_cast<int>(newState)));
|
|
|
- }
|
|
|
-
|
|
|
- // 如果需要恢复,现在可以安全地调用恢复操作(因为updateSyncState现在在锁外被调用)
|
|
|
- if (needRecovery) {
|
|
|
- performDelayedRecovery();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::updateStats() {
|
|
|
- // 统计信息在其他方法中已经更新
|
|
|
-}
|
|
|
-
|
|
|
-int64_t SynchronizerV2::smoothClock(ClockType type, int64_t newPts) {
|
|
|
- std::lock_guard<std::mutex> lock(historyMutex_);
|
|
|
-
|
|
|
- std::deque<int64_t>* history = nullptr;
|
|
|
- switch (type) {
|
|
|
- case ClockType::AUDIO:
|
|
|
- history = &audioClockHistory_;
|
|
|
- break;
|
|
|
- case ClockType::VIDEO:
|
|
|
- history = &videoClockHistory_;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return newPts;
|
|
|
- }
|
|
|
-
|
|
|
- if (history->empty() || newPts == AV_NOPTS_VALUE) {
|
|
|
- return newPts;
|
|
|
- }
|
|
|
-
|
|
|
- // 简单的指数移动平均
|
|
|
- int64_t lastSmoothed = history->back();
|
|
|
- if (lastSmoothed == AV_NOPTS_VALUE) {
|
|
|
- return newPts;
|
|
|
- }
|
|
|
-
|
|
|
- double smoothed = static_cast<double>(lastSmoothed) * (1.0 - config_.smoothingFactor) +
|
|
|
- static_cast<double>(newPts) * config_.smoothingFactor;
|
|
|
- return static_cast<int64_t>(smoothed);
|
|
|
-}
|
|
|
-
|
|
|
-int64_t SynchronizerV2::predictClock(ClockType type, double futureTime) const {
|
|
|
- // 注意:此方法假设调用者已经持有clockMutex_锁
|
|
|
- // 不能再调用getClock,否则会导致死锁
|
|
|
-
|
|
|
- const ClockInfo* clock = nullptr;
|
|
|
- switch (type) {
|
|
|
- case ClockType::AUDIO:
|
|
|
- clock = &audioClock_;
|
|
|
- break;
|
|
|
- case ClockType::VIDEO:
|
|
|
- clock = &videoClock_;
|
|
|
- break;
|
|
|
- case ClockType::EXTERNAL:
|
|
|
- clock = &externalClock_;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return AV_NOPTS_VALUE;
|
|
|
- }
|
|
|
-
|
|
|
- if (clock->paused || std::isnan(clock->pts)) {
|
|
|
- return static_cast<int64_t>(clock->pts * AV_TIME_BASE);
|
|
|
- }
|
|
|
-
|
|
|
- // 计算当前时间(不调用getClock避免死锁),使用packets_sync.cpp的get_clock算法
|
|
|
- double currentTime = getSystemTime();
|
|
|
- // 使用packets_sync.cpp的算法:pts + pts_drift + (current_time - last_updated) * speed
|
|
|
- double currentPtsSeconds = clock->pts + clock->pts_drift + (currentTime - clock->lastUpdate) * clock->speed;
|
|
|
-
|
|
|
- return static_cast<int64_t>((currentPtsSeconds + futureTime * clock->speed) * AV_TIME_BASE);
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::updateClockHistory(ClockType type, int64_t pts) {
|
|
|
- std::lock_guard<std::mutex> lock(historyMutex_);
|
|
|
-
|
|
|
- std::deque<int64_t>* history = nullptr;
|
|
|
- switch (type) {
|
|
|
- case ClockType::AUDIO:
|
|
|
- history = &audioClockHistory_;
|
|
|
- break;
|
|
|
- case ClockType::VIDEO:
|
|
|
- history = &videoClockHistory_;
|
|
|
- break;
|
|
|
- default:
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- history->push_back(pts);
|
|
|
- while (history->size() > static_cast<size_t>(config_.smoothingWindow)) {
|
|
|
- history->pop_front();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::attemptRecovery() {
|
|
|
- recoveryAttempts_++;
|
|
|
- lastRecoveryTime_ = std::chrono::steady_clock::now();
|
|
|
-
|
|
|
- Logger::instance().warning("Attempting sync recovery, attempt: " + std::to_string(recoveryAttempts_));
|
|
|
-
|
|
|
- // 重置时钟漂移
|
|
|
- {
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
- audioClock_.drift = 0.0;
|
|
|
- videoClock_.drift = 0.0;
|
|
|
- externalClock_.drift = 0.0;
|
|
|
- }
|
|
|
-
|
|
|
- // 可能需要重新选择主时钟(在锁外面调用避免死锁)
|
|
|
- if (config_.enableAdaptiveSync) {
|
|
|
- selectMasterClock();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::performDelayedRecovery() {
|
|
|
- // 这个方法在不持有clockMutex_的情况下被调用
|
|
|
- // 执行实际的恢复操作
|
|
|
-
|
|
|
- // 检查恢复间隔,避免过于频繁的恢复
|
|
|
- auto now = std::chrono::steady_clock::now();
|
|
|
- auto timeSinceLastRecovery = std::chrono::duration<double>(now - lastRecoveryTime_).count();
|
|
|
- if (timeSinceLastRecovery < 1.0) { // 至少间隔1秒
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- recoveryAttempts_++;
|
|
|
- lastRecoveryTime_ = now;
|
|
|
-
|
|
|
- Logger::instance().warning("Performing delayed sync recovery, attempt: " + std::to_string(recoveryAttempts_));
|
|
|
-
|
|
|
- // 重置时钟漂移
|
|
|
- {
|
|
|
- std::lock_guard<std::mutex> lock(clockMutex_);
|
|
|
- audioClock_.drift = 0.0;
|
|
|
- videoClock_.drift = 0.0;
|
|
|
- externalClock_.drift = 0.0;
|
|
|
- }
|
|
|
-
|
|
|
- // 只有在恢复次数较少时才重新选择主时钟,避免频繁切换
|
|
|
- if (config_.enableAdaptiveSync && recoveryAttempts_ <= 3) {
|
|
|
- selectMasterClock();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-double SynchronizerV2::getCurrentTime() const {
|
|
|
- auto now = std::chrono::steady_clock::now();
|
|
|
- return std::chrono::duration<double>(now - startTime_).count();
|
|
|
-}
|
|
|
-
|
|
|
-double SynchronizerV2::getSystemTime() const {
|
|
|
- return av_gettime_relative() / 1000000.0;
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::notifyStateChange(SyncState newState) {
|
|
|
- if (syncEventCallback_) {
|
|
|
- syncEventCallback_(state_, newState);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::notifyFrameDrop(ClockType type, int64_t pts) {
|
|
|
- if (frameDropCallback_) {
|
|
|
- frameDropCallback_(type, pts);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::notifyFrameDuplicate(ClockType type, int64_t pts) {
|
|
|
- if (frameDuplicateCallback_) {
|
|
|
- frameDuplicateCallback_(type, pts);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void SynchronizerV2::notifySyncError(double error, const std::string& reason) {
|
|
|
- if (syncErrorCallback_) {
|
|
|
- syncErrorCallback_(error, reason);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// PTS转换辅助方法实现
|
|
|
-double SynchronizerV2::ptsToSeconds(int64_t pts, double timeBase) const {
|
|
|
- if (pts == AV_NOPTS_VALUE) {
|
|
|
- return 0.0;
|
|
|
- }
|
|
|
- return pts * timeBase;
|
|
|
-}
|
|
|
-
|
|
|
-int64_t SynchronizerV2::secondsToPts(double seconds, double timeBase) const {
|
|
|
- if (timeBase <= 0.0) {
|
|
|
- return AV_NOPTS_VALUE;
|
|
|
- }
|
|
|
- return static_cast<int64_t>(seconds / timeBase);
|
|
|
-}
|
|
|
-
|
|
|
-} // namespace utils
|
|
|
-} // namespace av
|