New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[osx] Force reset in VideoSyncCocoa when refresh rate changes #6359
Conversation
is this really needed after #6356 ? |
if (!m_displayLost) | ||
{ | ||
m_displayLost = true; | ||
m_lostEvent.Wait(); |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
I'll check with #6356 tomorrow and let you know, but I suspect they both are needed. As noted, the reference clock will not be updated if the refresh rate changes after it was initialized. |
f2c7505
to
ff39dc9
Compare
Updated to ignore OnLostDevice. Checking in combination with #6356 now. |
With this PR plus #6356 I still have to bring up the VideoOSD (press 'm') to get it to sync up. At initial setup it says:
^^^^^ note this is the first detection, and it's wrong
^^^^^ detected the correct refresh rate here, and set the reference clock
^^^^^ I hit 'm' here to bring up the VideoOSD, and it sync'ed everything up. Prior to that, the audio was not in sync with the video. |
I don't think that the remaining issue is related to the clock. you were testing with vda, right? what if you switch off vda? |
Same thing. With or without vda, the audio is out of sync until i press 'm' to bring up VideoOSD. |
can you post a debug log which includes pressing m |
i don't get it - this was implemented like done in DRM https://github.com/xbmc/xbmc/blob/master/xbmc/video/videosync/VideoSyncCocoa.cpp#L140 this aborts the thread on resetdisplay - so why does that not work? |
refreshchanged method seems to be unused in this pr now |
@FernetMenta, sorry for the delay, had to go to bed.. here you go http://pastebin.com/vfngg8vY That log shows a few things:
|
@Memphiz, the whole problem is that it doesn't correctly identify the refresh rate when setting things up, because it's racing against the display change (and wins), I had to make the vblank handler set m_resetDisplay to true when the resolution change actually finishes. Without this patch, it just sets m_fps in VideoSyncCocoa but it is never fed back to the reference clock, so the codec info overlay reports that the display is at 60Hz. |
ff39dc9
to
2423e8e
Compare
I went through looking for commits that were seemingly/potentially related to A/V sync, which amounted to: de25db1 dvdplayer: discard render buffers if gui is not active I branched from the Helix branch and applied all of the above. Without my patch, it never gets the refresh rate right (stays at 60). With my patch (plus the above commits), it's better, but if I don't set the "Pause playback during refresh rate change" option to at least 2 seconds, it's wildly out of sync and won't dial back in (pressing 'm' does sync it up though). Even with the pause it's a small bit out of sync, but it corrects for it within a few seconds or so. |
when it's out of sync, is audio early or late? we need to find out why pressing m syncs up. what if you disable "sync playback to display"? |
It's early in both cases (with and without "sync playback to display"). And in both cases, pressing 'm' causes it to sync up. |
could you please disable "sync playback", enable verbose logging for video and post debug log which includes the issue EDIT: without vda, full debug log please |
Will do in just a minute. Wanted to show this one to you too first. Last night we watched a show and I noticed it took a full minute to figure out what the display's refresh rate was.. maybe something is wrong with the way Cocoa_GetCVDisplayLinkRefreshPeriod() detects the refresh rate, or a bug in OSX, I don't know. Also, for some reason the audio cut out twice (log says device list changed, so it closed the stream and reopened). This also caused the audio and video to go out of sync (again, pressing 'm' sync'ed it back up). |
please don't cut the logs |
I just tried without VDA and 'sync playback' (but with the above patches) and could not reproduce the A/V sync issue. So I re-enabled 'sync playback' and it still works. I then re-enabled VDA and the problem is back immediately. Disabled it again, and it's gone. So it's definitely something to do with VDA. I checked again with the official 14.1 release and it reports 60Hz again in the codec overlay (the issue my patch addresses). Different issue, but wanted to verify that my patch here was in fact still necessary without VDA. This is with my patch and the aforementioned commits. Without my patch at least, I can't tell if disabling VDA solves the A/V sync issue because it's syncing to the wrong rate (60Hz instead of 24Hz). I'll get full logs next time. Was trying to give you just the portion that showed the issue (we watched several shows last night), but I understand. |
this is an old vda issue. have you tried switching to ffmpeg vda. current vda will die soon after I have got my Mac. |
I haven't tried that. How would I go about switching to ffmpeg vda? edit: Nevermind, I found it in the sources. Trying now.. |
It works with "useffmpegvda" enabled. The only remaining issue seems to be that it can take a long time to detect the refresh rate change. The log below shows it taking 20 seconds to figure it out, but I've seen it take upwards of a minute as well. This could be an OSX thing though, I don't know. Besides that though, with my patch (and your patches noted above) and "useffmpegvda" enabled, it seems to be working normally. |
Hmm, I think I know how I can fix the remaining issue. Right now, Cocoa_GetCVDisplayLinkRefreshPeriod() returns a hard-coded value of 60.0 when CVDisplayLinkGetActualOutputVideoRefreshPeriod() returns <= 0.0. Instead, it should probably return the anticipated refresh rate; that is, the refresh rate associated with the resolution found in ChooseBestResolution(). This way, even if the OS doesn't quite know what the refresh rate currently is, at least the video won't appear 'jerky' to the user. If I'm off-base, let me know; otherwise, I can look into implementing it this way. |
video ref clock should not call Cocoa_GetCVDisplayLinkRefreshPeriod at all. GraphicsContext should be single source of truth (see DRM) Windowing for Darwin should have a mechanism to listen to internal and external triggered changes of refresh rate. see Linux X11. While playing a video you can change refresh rate externally with i.e. xrandr. |
It currently does, though. When setting things up, it calls CVideoReferenceClock::UpdateRefreshrate() which in turn calls m_pVideoSync->GetFps(), which on Darwin calls Cocoa_GetCVDisplayLinkRefreshPeriod() for its own return value. If I'm understanding all of this right, you're suggesting that CVideoSyncCocoa::GetFps() should just return g_graphicsContext.GetFPS()? Assuming g_graphicsContext.GetFPS() returns the correct value anyway. I can try this when I get home if I have this right. |
yes. and in case g_graphicsContext.GetFPS returns not the correct value, it needs to be fixed. |
Ok, I'll test this either tonight or tomorrow morning then. Valentine's Day dinner tonight with the wife so she may not let me spend time on it until tomorrow :) |
Mhhh well Cocoa_GetCVDisplayLinkRefreshPeriod calculates the refreshrate based on the displaylink vsync callback of the os. If this is not what it should do then we could get rid of alot of code indeed. And of course is osx windowing knowing when the video mode changes - thats why it implements IDispResource. I think i am missing a big point in this whole idea. To me it always seamed that everything we need for osx is available already - its just that components don't play together as they should it seems. Most likely because something is implemented not like its ment to be. |
thanks. this looks ok to me |
Awesome. Want me to rebase and squash then? |
lets wait for @Memphiz to comment. he can decide whether we can drop rounding for ios too |
|
||
bool CVideoSyncCocoa::Setup(PUPDATECLOCK func) | ||
{ | ||
CLog::Log(LOGDEBUG, "CVideoSyncCocoa: setting up Cocoa"); | ||
CLog::Log(LOGDEBUG, "CVideoSyncCocoa::%s - setting up Cocoa", __FUNCTION__); | ||
bool setupOk = false; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Consider graphicsContext as single-source-of-truth for the refresh rate instead of returning Cocoa_GetCVDisplayLinkRefreshPeriod() in CVideoSyncCocoa::GetFps().
i have no clue - @davilla wrote that code - maybe he can ask mr. goldfish what was the reason for the rounding |
we had this for all platforms, ancient xrandr and Windows only returned int. I have changed the video ref clock to operate with float. All platforms capable of delivering float should do so. |
too long ago, I'm sure there was a reason as I tend to stay away from MathUtils::round_int unless I absolutely need it to make something work correctly. |
https://github.com/xbmc/xbmc/blob/Gotham/xbmc/video/VideoReferenceClock.h#L96 |
fine by me then |
for ios too of course |
19ff8f8
to
2e7ed31
Compare
Done. |
jenkins build this please |
1 similar comment
jenkins build this please |
@jingai - you made the vblankhandler method osx only by moving the #endif - but its called from ios - thats why ios failed to link |
@jingai - nvm its a leftover - you need to remove the m_videosync member from ios windowing and also the call to vblankhandler in ioseaglview - i can do it later today |
Yeah, it didn't appear to be applicable to iOS so it seemed reasonable. I haven't built for iOS so I didn't notice that, sorry. I can add those changes to this PR but I wouldn't be able to do it until later today either. |
There, I just reverted that. It belongs in the cleanup commit you're going to make anyway. |
@jingai i had a talk with fernetmenta on irc and i have the bigger picture now. I hope you are not mad at me but i will refactor the implementations of videosync for cocoa and ios into 2 seperate implementations and clean it up. Thx a lot for pointing out the fix for osx (relying on fps from graphicscontext that is) - without your afford i wouldn't have looked into it. While its a bit demotivating for sure that your work seems unused now - believe me it was more then welcome and helpfull. |
Oh it doesn't bother me at all so long as it gets fixed :) It's been in a semi-non-functional state for a while now and it just bothered me enough to look into it. Let me know when you've got something to test and I'll check it on my end too. |
@jingai you could already give this a shot if you want (osx only for now - will do ios now...) |
@Memphiz, so far so good. Working exactly as my patches did. I'll keep an eye on your branch and test as it comes along. |
The existing implementation just updates m_fps, but nothing is fed back to the reference clock. Instead of calling UpdateFPS(), just force a reset, as it does in VideoSyncD3D.
This PR makes refresh rate adjustment work on OSX, which was the intended fix in PR #6146 / #6147.
However, it's a little suboptimal because the first time it goes to set things up, the call to CVDisplayLinkGetActualOutputVideoRefreshPeriod() in Cocoa_GetCVDisplayLinkRefreshPeriod() returns 0.0, which makes Cocoa_GetCVDisplayLinkRefreshPeriod() default to a return value of 60.0. So the video reference clock is set to 60.0 right off the bat.
In reality, the display is just in the process of switching over (which can take seconds on some TVs), so this means for every video played where refresh rate adjustment is required, it has to create the device, destroy it, and create it again.
Additionally, the audio is out of sync even after it does figure things out. Pressing 'm' to bring up VideoOSD forces it to sync up, but it's a little annoying to have to do that every time. [side note: what function is called to force-sync things when VideoOSD is brought up?]
I'm soliciting some discussion about how this should really be handled properly. Ideally, I think it should only set things up after the resolution change has completed (that is, CVDisplayLinkGetActualOutputVideoRefreshPeriod() returns > 0.0) to avoid creating and destroying things more than necessary (to speed up the start of playback). But it also needs to handle refresh rate/resolution changes on-the-fly as well (i.e., getting audio and video back in sync if the user just changes the refresh rate outside of Kodi, without requiring the user to bring up VideoOSD or some other UI element that forces a resync).