kingslay / KSPlayer

A video player for iOS、macOS、tvOS、visionOS , based on AVPlayer and FFmpeg, support the horizontal, vertical screen. support adjust volume, brightness and seek by slide, SwiftUI, support subtitles.
https://apps.apple.com/app/tracyplayer/id6450770064
GNU General Public License v3.0
996 stars 199 forks source link

Problem with 25fps on 60Hz TV with 2022 Apple TV 4K (heavy stuttering) #815

Open DrHurt opened 6 days ago

DrHurt commented 6 days ago

Test link: (25fps live stream) https://live-hls-web-aje-fa.getaj.net/AJE/01.m3u8

Playing Al Jazeera on Apple TV connected to Philips TV running at 60Hz results in stutter. Very obvious looking at the scrolling news ticker at the bottom.

Problem ONLY with ksplayer. Changing to AVPlayer WORKS perfect! Alternatively changing TV to 50Hz WORKS perfect. Also playing 24fps/30fps/60fps WORKS perfect.

I tried enabling/disabling of Asynchronous Decompression, Use DisplayLayer, Enable displayLink preferredFrame.

I suspect the problem is related to synchronising frame drawing by ksplayer to TV drawing (CADisplayLink problem?) when playing 25fps.

I'm sure all of us European users will be very happy if you fix this!

Thank you

DrHurt commented 5 days ago

I have done more testing: AVPlayer -> perfectly smooth on 60Hz VLC -> smooth on 60Hz MPV -> medium stutter on 60Hz KSPlayer -> heavy stutter / unwatchable on 60Hz, BUT switch TV to 50Hz -> KSPlayer is perfectly smooth!!

Interesting Discovery: iOS AVPlayer supports .ts streams!!! containing hevc/avc and aac/ac3

If you rename http://xxx/video.ts to http://xxx/video.m3u it works perfectly with avplayer. No need to convert or encode, just change extension.

Maybe KSPlayer should use avplayer by default for ts streams (like it does with m3u currently)

kingslay commented 5 days ago

我改了下代码,你用test flight包试下(Build 2.4.4 (2) )。并且把 displayLink preferredFrame 这个开关打开。看下有没有变得顺滑一点。

DrHurt commented 5 days ago

I did the testing using 2.4.4 (276) from test flight.

It feels like displayLink preferredFrame makes the problem slightly worse

cdguy commented 5 days ago

I did the testing using 2.4.4 (276) from test flight.

It feels like displayLink preferredFrame makes the problem slightly worse

Have you tried with “ Match Frame Rate” set to ON?

https://support.apple.com/en-us/102277

If it is disabled it is normal that a PAL content would stutter on a NTSC format (60hz)

DrHurt commented 5 days ago

I’m well aware of the judder caused by 25 not fitting into 60 but that’s not what’s happening here. KSPlayer seems to have another bigger problem with 25fps on 60Hz where other players don’t.

I think I found the problem: It’s caused by KSPlayer “audio video sync” causing display FPS to fluctuate to stay in sync with audio

This is probably confusing my TV motion processing algorithms which causes stutter/tearing.

Can we get a test with AV sync disabled so framerate stays constant? (Or maybe force constant 25fps)

I’ll do more testing later with video without no sound track to confirm!

cdguy commented 5 days ago

I’m well aware of the judder caused by 25 not fitting into 60 but that’s not what’s happening here. KSPlayer seems to have another bigger problem with 25fps on 60Hz where other players don’t.

I think I found the problem: It’s caused by KSPlayer “audio video sync” causing display FPS to fluctuate to stay in sync with audio

This is probably confusing my TV motion processing algorithms which causes stutter/tearing.

Can we get a test with AV sync disabled so framerate stays constant? (Or maybe force constant 25fps)

I’ll do more testing later with video without no sound track to confirm!

VLC and MPV does not support match rate, hence in the backend those apps multiply the number of frames to match the screen refresh rate but at a cost of reducing image quality

You will see that if you enable the toggle I shared above the image will be smooth

cdguy commented 5 days ago

I’m well aware of the judder caused by 25 not fitting into 60 but that’s not what’s happening here. KSPlayer seems to have another bigger problem with 25fps on 60Hz where other players don’t.

I think I found the problem: It’s caused by KSPlayer “audio video sync” causing display FPS to fluctuate to stay in sync with audio

This is probably confusing my TV motion processing algorithms which causes stutter/tearing.

Can we get a test with AV sync disabled so framerate stays constant? (Or maybe force constant 25fps)

I’ll do more testing later with video without no sound track to confirm!

And not every stream is in 50hz, some will be in 60hz; so to have the best experience in terms of smoothness you have to enable match frame rate in the ATV settings

cdguy commented 5 days ago

And, in KSplayer, this is managed by AVDisplayCriteria But it checks first if you have enabled “dynamic range” and “frame match” in ATV settings

DrHurt commented 5 days ago

You are missing the point my friend and going off topic! I’m aware of everything you say!

I’m simply suggesting that there’s a bug with KSPlayer where in trying to maintain av sync, it’s causing output framerate to irregularly fluctuate which on my Philips TV causes more stutters than expected.

I’ll do more objective testing later today and share my results here. That’ll be my small contribution to this great project.

kingslay commented 5 days ago

I did the testing using 2.4.4 (276) from test flight.

It feels like displayLink preferredFrame makes the problem slightly worse

@DrHurt 因为Xcode cloud打包失败了。所以我今天是本地打包的,一定要用Build 2.4.4 (2) 这个版本才可以,2.4.4 (2) 才是最新的版本,不能用2.4.4 (276) 。 你在tvos的testflight可以看到 2.4.4 (2) 吗?

DrHurt commented 5 days ago

I did the testing using 2.4.4 (276) from test flight. It feels like displayLink preferredFrame makes the problem slightly worse

@DrHurt 因为Xcode cloud打包失败了。所以我今天是本地打包的,一定要用Build 2.4.4 (2) 这个版本才可以,2.4.4 (2) 才是最新的版本,不能用2.4.4 (276) 。 你在tvos的testflight可以看到 2.4.4 (2) 吗?

I cannot see 2.4.4 (2) on TestFlight.

PROBLEM CONFIRMED: 25fps with audio track == stutter 25fps with NO audio track == smooth

I believe KSPlayer is changing output frame rate while trying to keep audio and video in sync.

Perhaps you could add an option to disable audio video sync correction for now.

And if a user really needs it, KSPlayer can change audio speed instead of video frame rate.

Attached are 3 files: WithAudio.mp4 == stutter NoAudio.mp4 == smooth Demo.mp4 to show how it looks on my TV (much worse in person)

Note another bug, when playing NoAudio.mp4, it shows Display FPS = 30 (which is wrong)

https://drive.google.com/file/d/1nCA67hUOk9jdsYtICuJAujf-HH2OKQEE/view?usp=sharing

cdguy commented 5 days ago

I did the testing using 2.4.4 (276) from test flight. It feels like displayLink preferredFrame makes the problem slightly worse

@DrHurt 因为Xcode cloud打包失败了。所以我今天是本地打包的,一定要用Build 2.4.4 (2) 这个版本才可以,2.4.4 (2) 才是最新的版本,不能用2.4.4 (276) 。 你在tvos的testflight可以看到 2.4.4 (2) 吗?

I cannot see 2.4.4 (2) on TestFlight.

PROBLEM CONFIRMED: 25fps with audio track == stutter 25fps with NO audio track == smooth

I believe KSPlayer is changing output frame rate while trying to keep audio and video in sync.

Perhaps you could add an option to disable audio video sync correction for now.

And if a user really needs it, KSPlayer can change audio speed instead of video frame rate.

Attached are 3 files: WithAudio.mp4 == stutter NoAudio.mp4 == smooth Demo.mp4 to show how it looks on my TV (much worse in person)

Note another bug, when playing NoAudio.mp4, it shows Display FPS = 30 (which is wrong)

https://drive.google.com/file/d/1nCA67hUOk9jdsYtICuJAujf-HH2OKQEE/view?usp=sharing

@kingslay I confirm that when you play the video “WithAudio.mp4” there are stutters. It is easier to notice it when you play the video at x2 speed

cdguy commented 5 days ago

@kingslay i used those settings

IMG_4995

using displaylink preferredFrame makes it worse

kingslay commented 4 days ago

@DrHurt 你看下是否可以看到 2.4.4 (288)这个版本。可以的话,那把 displayLink preferredFrame 这个开关打开。测试下。

cdguy commented 4 days ago

你看下是否可以看到 2.4.4 (288)这个版本。可以的话,那把 displayLink preferredFrame 这个开关打开。测试下。

It worked fine on my side, @DrHurt can you also try it?

DrHurt commented 4 days ago

@DrHurt 你看下是否可以看到 2.4.4 (288)这个版本。可以的话,那把 displayLink preferredFrame 这个开关打开。测试下。

Unfortunately not fixed here with 288

Findings so far: (First Player Type = KSPlayer in settings because this is what it uses with ts live streams)

Thinking out loud here, but I feel this 30fps bug is related. Why 30fps specifically? Is is hardcoded? Is it a stray variable somewhere in the code?

Adding the audio track slows it down to 25fps. Is KSPlayer is trying to slow down the video to match audio causing stuttering? Maybe if this is fixed, it will fix the stuttering?

Attached are 2 more files as an example. Look at the scrolling news ticker at the bottom. https://drive.google.com/file/d/166brl9R6E47-PYnX2inHppkWQcuo_gLb/view?usp=sharing

kingslay commented 4 days ago

@DrHurt 视频的展示需要等待音频,这样才不会有音视频不一致的问题。我用你给的SkyNoAudio 和SkyWithAudio 在preferredFrame 开启的情况下。日志显示每个视频帧显示的间隔是很平均的。所以应该是顺畅的。 @cdguy 麻烦你也试下这两个视频。看下会不会顺畅。 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03978395834565163 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03979429160244763 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03973166667856276 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.04018949996680021 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039325833320617676 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03990291664376855 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039741375017911196 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03982249996624887 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03976383316330612 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039663333212956786 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03983716666698456 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03975879168137908 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03968283347785473 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03993795835413039 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03973370813764632 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03972462494857609 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03987420839257538 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03972887503914535 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039944166550412774 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.0395286250859499 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039920249953866005 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03995670843869448 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03965212497860193 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03970375005155802 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03968204162083566 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039921333314850926 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039765708381310105 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03977945842780173 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039889583364129066 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03953749989159405 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03988879150711 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03977916669100523 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03986370819620788 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.03978712507523596 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039719375083222985 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039674000116065145 video diff 0.03999999999999915 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.039698250126093626 video diff 0.040000000000000924 warning KSPlayer: MEPlayerItem.swift:1048 setVideo(time:position:) | [video] video interval 0.0398119583260268 video diff 0.03999999999999915

DrHurt commented 4 days ago

But why is SkyNoAudio playing at 30fps with KSPlayer? Changing First Player Type = AVPlayer it plays normally at 25fps and smoothly.

It's smooth for cdguy because he has his TV set to 50Hz, while I have mine at 60Hz (smoother UI).

cdguy commented 4 days ago

@DrHurt 视频的展示需要等待音频,这样才不会有音视频不一致的问题。我用你给的SkyNoAudio 和SkyWithAudio 在preferredFrame 开启的情况下。日志显示每个视频帧显示的间隔是很平均的。所以应该是顺畅的。 @cdguy 麻烦你也试下这两个视频。看下会不会顺畅。

@kingslay as I said, yesterday I tried both videos and your fix fixed the stutters on tvos. As we spoke yesterday, I know you are trying to find a fix for ios.

my tv settings were (via appleTV settings): 4K HDR 50hz + Dynamic Range ON + Frame Matching ON I also turned off all picture correction features such as “motion plus” etc

cdguy commented 4 days ago

But why is SkyNoAudio playing at 30fps with KSPlayer? Changing First Player Type = AVPlayer it plays normally at 25fps and smoothly.

It's smooth for cdguy because he has his TV set to 50Hz, while I have mine at 60Hz (smoother UI).

There is something wrong with your setup. When I set the ATV to 60hz with FPS matching ON it is smooth

also the “without audio” track plays at 50hz, as it should be

IMG_5027

DrHurt commented 4 days ago

@cdguy I’m talking about KSPlayer not the actual TV refresh rate.

I think I’ve narrowed it down even further.

Try the following: 1- TV set to 60Hz, match frame rate and dynamic range to off. 2- Play SkyNoAudio and press the i (information) and see track info will say 25fps but “Display FPS” will say ~30 and video will play quickly 3- Change TV to 50Hz and do the same, Display FPS will change to ~25 and video will play at normal speed.

So the bug seems to be that KSPlayer will decode the video at a rate equal to half the display Hz.

See screenshot playing 25fps on 60Hz and note the “Display FPS” at the bottom.

IMG_1438

kingslay commented 4 days ago

@DrHurt 当你的tvOS是只是为60hz的话,那需要把 match frame rate and dynamic range 打开,这样才能顺畅的播放25fps。我测试了不用打开 displayLink preferredFrame. 也是可以顺畅的。并且display fps也是显示为25.

所以重点是一定要打开 match frame rate and dynamic range

你们的tvOS正常会开启 match frame rate and dynamic range吗?

kingslay commented 4 days ago

我也会看下 为什么 SkyNoAudio播放, display fps什么会显示为30. 确实应该是25.

cdguy commented 3 days ago

我也会看下 为什么 SkyNoAudio播放, display fps什么会显示为30. 确实应该是25.

Thank you for the new testflight app It is fixed now

kingslay commented 3 days ago

@DrHurt 你可以试下最新的test flight包, 目前SkyNoAudio 在tvOS 和iOS 上,不管如何设置,都可以让display fps 可以显示为25fps了。但是播放还是无法非常流畅,除非在tvOS上开启 match frame rate and dynamic range

DrHurt commented 3 days ago

@DrHurt 你可以试下最新的test flight包, 目前SkyNoAudio 在tvOS 和iOS 上,不管如何设置,都可以让display fps 可以显示为25fps了。但是播放还是无法非常流畅,除非在tvOS上开启 match frame rate and dynamic range

partially fixed: SkyNoAudio - smooth, playing at correct speed now (25fps on 60Hz) SkyWithAudio - stutter

displayLink preferredFrame makes everything worse so I have disable it.

Narrowing it down even further:

Definitely getting closer 👍

cdguy commented 2 days ago

@DrHurt 你可以试下最新的test flight包, 目前SkyNoAudio 在tvOS 和iOS 上,不管如何设置,都可以让display fps 可以显示为25fps了。但是播放还是无法非常流畅,除非在tvOS上开启 match frame rate and dynamic range

partially fixed: SkyNoAudio - smooth, playing at correct speed now (25fps on 60Hz) SkyWithAudio - stutter

displayLink preferredFrame makes everything worse so I have disable it.

Narrowing it down even further:

  • Audio set to AudioUnit - SkyWithAudio == smooth (FINALLY!)
  • Audio set to (default) AVAudioEngine SkyWithAudio == stutter

Definitely getting closer 👍

Have you tried with AudioRenderer? This is the only audio decoder that supports spatial audio on tvos @DrHurt

kingslay commented 2 days ago

@DrHurt 我刚增加了一个开关 Enable audio VideoClock Sync。 你用最新的test flight包2.4.6 (291) 试下

DrHurt commented 2 days ago

The latest version on TestFlight is 2.4.4 (289)

I will wait for the new version and let you know.

DrHurt commented 2 days ago

@DrHurt 我刚增加了一个开关 Enable audio VideoClock Sync。 你用最新的test flight包2.4.6 (291) 试下

Tested now and videos are PERFECTLY SMOOTH with all audio engines 👍 And videos load much more quickly now.

As to be expected, audio video sync has been a bit erratic, but at least we now know the root of the problem.

With TV speakers: videos are smooth with all audio engines. AVAudioEngine causes some video sync problems, other engines seem acceptable.

With HomePod as speaker: all audio engines seem to struggle with video sync. AVSampleBufferAudioRenderer doesn't work with live streams when connected to HomePod so couldn't test (keeps buffering). Can that be fixed? It works perfectly with mp4 for some reason.

I'll do more testing tomorrow, but significant progress here!!

cdguy commented 2 days ago

@kingslay @DrHurt I tried the video file “NoAudio.mp4” using the latest beta https://drive.google.com/file/d/1nCA67hUOk9jdsYtICuJAujf-HH2OKQEE/view?usp=sharing

On ios and ipados, if I use AudioUnit, there are no stutters, however when I use AudioRenderer there are stutters both on ios and ipados.

AudioRenderer is a must in Ksplayer because it uses the latest audio libraries of Apple and it has a better management of Spatial Audio

DrHurt commented 1 day ago

@kingslay I did more testing today:

audio VideClock Sync == off Videos are super smooth but as expected videos randomly go out of sync with audio. This is particularly bad with HomePods causing 2-3 second lag so it not useable for me. This happens with all engines but AVAudioEngine seems to be the worst.

audio VideoClock Sync == on Videos stutter ONLY with AVAudioEngine. Video smooth with all other audio engines 👍

My suggestion: Until this AVAudioEngine sync bug is fixed, change the default audio engine in KSPlayer from AVAudioEngine to AudioUnit so that IPTV apps using KSPlayer would benefit from the improved 25fps playback. I have tested this with 25fps on 60Hz and HomePods and with 5.1 audio and everything works well.

@cdguy All the audio engines support multichannel in my limited testing but none support Atmos metadata. If you want proper atmos, you need to change First Player Type to AVPlayer (iOS native player) and use mp4 with the correct metadata. That's the only way to get my speakers to light up the "Atmos" indicator.

kingslay commented 1 day ago

@DrHurt 我刚增加了一个开关 Enable audio VideoClock Sync。 你用最新的test flight包2.4.6 (291) 试下

Tested now and videos are PERFECTLY SMOOTH with all audio engines 👍 And videos load much more quickly now.

As to be expected, audio video sync has been a bit erratic, but at least we now know the root of the problem.

With TV speakers: videos are smooth with all audio engines. AVAudioEngine causes some video sync problems, other engines seem acceptable.

With HomePod as speaker: all audio engines seem to struggle with video sync. AVSampleBufferAudioRenderer doesn't work with live streams when connected to HomePod so couldn't test (keeps buffering). Can that be fixed? It works perfectly with mp4 for some reason.

I'll do more testing tomorrow, but significant progress here!!

@DrHurt 我刚更新了test flight包。解决了audio VideClock Sync == off 时,音频和视频不同步的问题。麻烦你试下。我也把默认的音频输出改成是AudioUnit了。我接下来会看下 AVAudioEngine ,AVSampleBufferAudioRenderer的问题

DrHurt commented 1 day ago

我刚更新了test flight包。解决了audio VideClock Sync == off 时,音频和视频不同步的问题。麻烦你试下。我也把默认的音频输出改成是AudioUnit了。我接下来会看下 AVAudioEngine ,AVSampleBufferAudioRenderer的问题

ALL FIXED 👍 👍 👍 audio VideClock Sync == off && AudioUnit --> smooth video, perfect sync (even with HomePods)

I think these should be the default settings now so IPTV apps can use them by default. (At the moment default is sync on)

Congratulations Kingslay