2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "VideoSyncOsx.h"
11 #include "ServiceBroker.h"
12 #include "cores/VideoPlayer/VideoReferenceClock.h"
13 #include "utils/MathUtils.h"
14 #include "utils/TimeUtils.h"
15 #include "utils/log.h"
16 #include "windowing/GraphicContext.h"
17 #include "windowing/WinSystem.h"
19 #include "platform/darwin/osx/CocoaInterface.h"
21 #include <CoreVideo/CVHostTime.h>
22 #include <QuartzCore/CVDisplayLink.h>
25 using namespace std::chrono_literals;
27 bool CVideoSyncOsx::Setup()
29 CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} setting up OSX", __FUNCTION__);
31 //init the vblank timestamp
33 m_displayLost = false;
34 m_displayReset = false;
37 CServiceBroker::GetWinSystem()->Register(this);
42 void CVideoSyncOsx::Run(CEvent& stopEvent)
46 //because cocoa has a vblank callback, we just keep sleeping until we're asked to stop the thread
47 while(!stopEvent.Signaled() && !m_displayLost && !m_displayReset)
54 while(!stopEvent.Signaled() && m_displayLost && !m_displayReset)
62 void CVideoSyncOsx::Cleanup()
64 CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} cleaning up OSX", __FUNCTION__);
67 CServiceBroker::GetWinSystem()->Unregister(this);
70 float CVideoSyncOsx::GetFps()
72 m_fps = CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS();
73 CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} Detected refreshrate: {:f} hertz", __FUNCTION__, m_fps);
77 void CVideoSyncOsx::RefreshChanged()
79 m_displayReset = true;
82 void CVideoSyncOsx::OnLostDisplay()
87 m_lostEvent.Wait(1000ms);
91 void CVideoSyncOsx::OnResetDisplay()
93 m_displayReset = true;
96 void CVideoSyncOsx::VblankHandler(int64_t nowtime, uint32_t timebase)
100 int64_t Now = CurrentHostCounter();
102 if (m_LastVBlankTime != 0)
104 VBlankTime = (double)(nowtime - m_LastVBlankTime) / (double)timebase;
105 NrVBlanks = MathUtils::round_int(VBlankTime * static_cast<double>(m_fps));
107 //update the vblank timestamp, update the clock and send a signal that we got a vblank
108 m_refClock->UpdateClock(NrVBlanks, Now);
111 //save the timestamp of this vblank so we can calculate how many happened next time
112 m_LastVBlankTime = nowtime;
115 // Called by the Core Video Display Link whenever it's appropriate to render a frame.
116 static CVReturn DisplayLinkCallBack(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
120 CVideoSyncOsx* VideoSyncOsx = reinterpret_cast<CVideoSyncOsx*>(displayLinkContext);
122 if (inOutputTime->flags & kCVTimeStampHostTimeValid)
123 VideoSyncOsx->VblankHandler(inOutputTime->hostTime, CVGetHostClockFrequency());
125 VideoSyncOsx->VblankHandler(CVGetCurrentHostTime(), CVGetHostClockFrequency());
128 return kCVReturnSuccess;
131 bool CVideoSyncOsx::InitDisplayLink()
134 CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} setting up displaylink", __FUNCTION__);
136 if (!Cocoa_CVDisplayLinkCreate((void*)DisplayLinkCallBack, reinterpret_cast<void*>(this)))
138 CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} Cocoa_CVDisplayLinkCreate failed", __FUNCTION__);
144 void CVideoSyncOsx::DeinitDisplayLink()
146 Cocoa_CVDisplayLinkRelease();