8#define LOC QString("AVSync: ")
24 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
"Reset");
29 auto unow = std::chrono::microseconds(
m_avTimer.nsecsElapsed() / 1000);
30 auto delay = FrameDue - unow;
32 std::this_thread::sleep_for(delay);
50 Map.insert(
"avsync", QObject::tr(
"%1 ms").arg(
m_avsyncAvg / 1000));
55 std::chrono::microseconds FrameInterval,
float PlaySpeed,
56 bool HaveVideo,
bool Force)
69 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Dropping short frame"));
75 std::chrono::milliseconds videotimecode = 0ms;
76 bool dropframe =
false;
77 bool pause_audio =
false;
78 std::chrono::microseconds framedue = 0us;
79 std::chrono::milliseconds audio_adjustment = 0ms;
80 std::chrono::microseconds unow = 0ms;
81 std::chrono::microseconds lateness = 0us;
83 auto intervalms = duration_cast<std::chrono::milliseconds>(FrameInterval);
85 static float const s_av_control_gain = 0.4F;
87 static float const s_sync_fc = 0.9F;
92 while (framedue == 0us)
96 videotimecode = std::chrono::milliseconds(
Frame->m_timecode.count() & 0x0000ffffffffffff);
98 if (videotimecode !=
Frame->m_timecode)
102 unow = std::chrono::microseconds(
m_avTimer.nsecsElapsed() / 1000);
106 framedue = unow + FrameInterval;
114 if (videotimecode == 0ms)
118 bool dataonly = !Audio->
HasAudioIn() && !HaveVideo;
122 if (videotimecode == 0ms && !dataonly)
125 m_rtcBase = unow - chronodivide<std::chrono::microseconds>(videotimecode, PlaySpeed);
131 if (videotimecode == 0ms)
133 std::chrono::milliseconds tcincr = videotimecode -
m_maxTcVal;
134 if (tcincr > 0ms || tcincr < -100ms)
145 if (PlaySpeed > 0.0F)
146 framedue =
m_rtcBase + chronodivide<std::chrono::microseconds>(videotimecode, PlaySpeed);
148 framedue = unow + FrameInterval / 2;
150 lateness = unow - framedue;
160 if (audio_adjustment < -200ms
164 audio_adjustment = 0ms;
166 int sign = audio_adjustment < 0ms ? -1 : 1;
167 float fix_amount_ms = (
m_lastFix * s_sync_fc + (1 - s_sync_fc) * audio_adjustment.count()) * sign * s_av_control_gain;
171 if ((audio_adjustment * sign) > intervalms)
173 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Audio %1 by %2 ms")
174 .arg(audio_adjustment > 0ms ?
"ahead" :
"behind").arg(abs(audio_adjustment.count())));
176 if (audio_adjustment > 200ms)
187 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Resetting: lateness %1").arg(lateness.count()));
190 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Resetting: lateness = %1").arg(lateness.count()));
205 || audio_adjustment < 0ms)
223 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Dropping frame: Video is behind by %1ms")
224 .arg(duration_cast<std::chrono::milliseconds>(lateness).count()));
230 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
LOC +
231 QString(
"A/V timecodes audio=%1 video=%2 frameinterval=%3 audioadj=%4 unow=%5 udue=%6 ")
233 .arg(audio_adjustment.count()).arg(unow.count()).arg(framedue.count()));
std::chrono::milliseconds GetAudioTime(void)
bool HasAudioIn(void) const
std::chrono::microseconds m_refreshInterval
void SetAVSyncMusicChoice(AudioPlayer *Audio)
void GetAVSyncData(InfoMap &Map) const
std::chrono::milliseconds m_priorAudioTimecode
AVSyncAudioPausedType m_avsyncAudioPaused
std::chrono::microseconds AVSync(AudioPlayer *Audio, MythVideoFrame *Frame, std::chrono::microseconds FrameInterval, float PlaySpeed, bool HaveVideo, bool Force)
std::chrono::milliseconds m_priorVideoTimecode
std::chrono::milliseconds m_dispTimecode
std::chrono::milliseconds m_maxTcVal
std::chrono::microseconds m_rtcBase
void ResetAVSyncForLiveTV(AudioPlayer *Audio)
void WaitForFrame(std::chrono::microseconds FrameDue)
std::chrono::microseconds m_shortFrameDeltas
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::microseconds > microsecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
static constexpr std::chrono::microseconds AVSYNC_MAX_LATE
@ kAVSyncAudioPausedLiveTV
QHash< QString, QString > InfoMap