PaulleDemon / tkVideoPlayer

Video player for tkinter.
MIT License
83 stars 25 forks source link

Framerate issues #15

Closed PaulleDemon closed 1 year ago

PaulleDemon commented 2 years ago

If you encounter any framerate-related issues, even after upgrading to the latest version, i.e the video being too fast or too slow, please comment under this. Before posting a comment make sure to test your video with other video players, (eg, VLC player), to make sure that it isn't related to hardware

flairekq commented 2 years ago

Hi, I am using the latest version to play the video and it's too slow by about half the original speed. I've tested it on other video player and it works fine.

PaulleDemon commented 2 years ago

@flairekq, thank you for letting me know. Can you also specify the duration, FPS, and quality (eg: 4k, 1080p, 720p etc)

flairekq commented 2 years ago

@PaulleDemon Hi I'm not really sure how to check the quality of the video (it's a self-recorded video using opencv) The duration is 34seconds and for the FPS (I used VLC to check):

image
Untitled15 commented 2 years ago

Hello, whenever I play a .mov or .mp4 file it goes too fast, how do I make the video display at normal speed?

PaulleDemon commented 2 years ago

@Untitled15 thank you for your report, I currently have a semester test, but I'll try to look into it by the end of this month

zyeborm commented 1 year ago

Just an example of a failing mp4 file. I generated it using davinci resolve (chopped out of youtube, a prior youtube video that hadn't been run through resolve worked fine (I think, I may have been using that on linux).

Had a bit more of a look. For reference I'm running this on windows.

If I change the line time.sleep(max(((time_in_frame - delta)/1000),0)) to time.sleep(0.025) it looks about right to me (on this machine, at this phase of the moon and temperature)

I tried debugging by printing then now and then-now to stdout but understandably that wasn't a great plan, it'd need to be buffered or written to file or some such and I'm lazy.

I have the feeling it's something to do with the time nanoseconds, threading and windows but I don't have a linux machine handy to test


update later. I changed that line to sleepuntil = ((time_in_frame) * self._frame_number) + self.start_time time.sleep(max(((sleepuntil-(time.time_ns() // 1000000))/1000),0))

I put this in the play function to set the start time. def play(self): self.start_time = time.time_ns() // 1_000_000

This isn't a general purpose fix, it worked for me in windows and will probably break anything that stops and starts the video. I suspect the issue is jitter in the get_ns function going outside the frame time and things getting "wonky". What my change does is calculate the sleep time based on the ideal frame rate rather than working it out incrementally. The jitter is still there but it averages out rather than adds up. A better answer would probably be to find a better time source in windows (and possibly combine that with a better implementation of this method, might help keep playback on an even time base even if there's momentary overload, it'll just run at minimum delay until it catches up )

https://user-images.githubusercontent.com/8118867/201888888-33b52e96-81be-4a0c-855b-767fdf4584f4.mp4

P.S Thanks for making this btw, got me out of a jam on a quickie project, I'm just doing this extra bit to say thanks ;-)

PaulleDemon commented 1 year ago

@zyeborm Thank you for taking the effort out to post this issue and for taking the time to look for a possible solution. I will be having semester exams over next couple of weeks, so I'll look into this after that. Thank you again.

Rueder commented 1 year ago

Hi im too having Problems with the framerate. Im programming on PC it runs just fine. Same script un PI 4 abaut half the fps. (no Frames get skipt) Video on PI with VNC- Player runs smoth Tryed using diffrent PIs didnt cange my video is mp4 with 25fps and 3s runtime an an ratio of 600x715 If i run it without scaling it runs fine even on PI. (but deformd in a 150 to 100 Box) your method videoplayer.set_size((600,715)) wont work on PC or PI but if i try to get the origenal size back with: videoplayer.place(x=0, y=0, width=600, height=715) it runs to slow. tried difrent videos with the same format with more runetime same problem.

havetc commented 1 year ago

Hello! I think I have found a solution, I just opened #28 with it. The idea is to keep a lag value, and if this lag start to become bigger than a frame_time then we skip a frame to reduce it, and if it is negative (which happens when delta < time_in_frame) then we sleep this amount of time.

havetc commented 1 year ago

New pull request, this time increasing greatly the performance especially for high resolutions #34

PaulleDemon commented 1 year ago

@havetc Will look into it as soon as I am free. Thank you for this pull request

havetc commented 1 year ago

Hello, just a reminder that it's now been more than two months since my first pull request, I'm still waiting for merges or for some feedback.

BennyBot commented 12 months ago

Encountered this issue on Windows 10 today. Videos were playing at ~2x the framerate they were supposed to be playing at (high 50s when the expected was 23fps). These videos are approximately 00:01:30 (hh/mm/ss) in length. I changed the lines using time.time_ns() to use time.process_time_ns() and this had good effects. Videos now played at ~0.97x their expected framerate, which is a lot closer than the original ~2x, but still not perfect. After some sleep deprived research looks like windows is just going to be inconsistent with the times returned by the time module. Not sure how to resolve the remaining framerate problem on windows, afaik it is due to small variance within time.process_time_ns() or time.sleep() (or probably both compounding).

havetc commented 12 months ago

@BennyBot could you try my master branch https://github.com/havetc/tkVideoPlayer ? It is up to date with this repo and contains edits I did in pull request #28 , which was rejected but should fix this problem. The problem with the current implementation is that any timing error is cumulative over time, whereas in my proposed implementation I keep track of the timing at a global basis and not just compared to previous frame.

time.process_time_ns() doesn't take into account slept time, looking at the current implementation it fixes a bug where slept time is counted as decoding time. Still, as time.sleep() cannot be guaranteed to be precise (the OS wakes up the process when it wants / can), your remaining 3% difference in expected framerate is not suprising. Also I think that the implementation cannot consider a float framerate, only an integer one, so in some cases that's a further deviation to the running framerate.

BennyBot commented 12 months ago

@BennyBot could you try my master branch https://github.com/havetc/tkVideoPlayer ? It is up to date with this repo and contains edits I did in pull request #28 , which was rejected but should fix this problem.

Just tried it on the same videos, slightly improved results at ~0.985x speed of the desired framerate. I had a quick glance at your changes and they make sense to me, not sure how to resolve the remaining 1.5%. However, for my use case this works great, thank you. Videos played are only 1-2 minutes in length, so audio desync is hardly noticeable.

havetc commented 12 months ago

@BennyBot Could you give me a link to one of those video? I'd be curious to find out what causes the remaining difference.

PaulleDemon commented 11 months ago

Just so you know PyPI release 2.5 has the latest commits and updates.