jaseg / python-mpv

Python interface to the awesome mpv media player
https://git.jaseg.de/python-mpv.git
Other
556 stars 69 forks source link

wait_until_playing() seems to be triggered too early #283

Closed jkh13 closed 4 months ago

jkh13 commented 4 months ago

I am trying to synchronise an LED flashing in time with the start of video playback using mpv and a raspberry pi, I add the video, pause at the start, unpause and call wait_until_playing() before executing the code to flash the LED.

The issue I am seeing is that wait_until_playing is returning an indeterministic amount of milliseconds before the video actually starts playing, I am measuring it to be about 150ms which is a lot higher than even the max response time of the monitor I am using and higher than expected even accounting for the timing issues python has with sleep() etc. This essentially results in the LED flash being triggered about 150ms before the video starts playing when it should be triggered exactly when the video frames are starting to be displayed.

If anything I was prepared for the wait until playing to trigger slightly after the video starts playing but it is actually triggering early. The code I am using to repro is as follows:

player = MPV(vo="gpu")
player.fullscreen = True
player.play('/home/pi/Downloads/test.mp4')    # h264 video
player.pause=True     # Pause on first frame
sleep(5)
player.pause=False
player.wait_until_playing()
#sleep(0.150)     # This sort of fixes the issue but of course the delay is not always exactly 150ms

flashLed()

Am I doing something incorrect here? is there another event I should wait for to determine when the video is actually started?

jaseg commented 4 months ago

wait_until_playing waits until mpv reports False on its core-idle property. That means it waits until the mpv core has started processing media, which on a weak sauce platform such as raspberry pi can be a while before anything is actually displayed on screen. For frame-exact synchronization, I'd recommend hooking into mpv's rendering API and doing the rendering yourself via OpenGL. This is the best way to get exact timing on a platform like a raspi, since all of the observer APIs process events after they happen on the python-mpv thread, which may lag by several seconds on something like a raspi when the CPU or storage are congested.

If you don't need things to be frame-exact, how about synchronizing your LED to the time-pos property, which indicates the playback position in the current file in floating-point seconds?

@player.property_observer('time-pos')
def update_led(_property_name, new_pos):
    state = 'on' if new_pos % 0.7 > 0.3 else 'off'
    print('LED ', state)
jaseg commented 4 months ago

(I'm guessing that your issue has been solved. Feel free to re-open this, or to open another issue if you have more questions :)