I've read similar questions that have been answered:
- Getting realtime output from ffmpeg to be used in progress bar (PyQt4, stdout)
- Progressbar to show amount of music played
- How to measure elapsed time in Python?
Here's my window:
Problem is song ends when counter still has 20% to go. I know the reason is primarily due to system call to check if process is still running pgrep ffplay
10 times every second. Secondary reason is simply Python and Tkinter overhead.
To "band-aid fix" the problem I used 1.24
deciseconds instead of 1
every decisecond as my code illustrates now:
def play_to_end(self):
'''
Play single song, checking status every decisecond
Called from:
self.play_forever() to start a new song
self.pp_toggle() to restart song after pausing
'''
while True:
if not self.top2_is_active: return # Play window closed?
root.update() # Process other events
if self.pp_state is "Paused":
time.sleep(.1) # Wait until playing
continue
PID = os.popen("pgrep ffplay").read() # Get PID for ffplay
if len(PID) < 2: # Has song ended?
return # Song has ended
#self.current_song_time += .1 # Add decisecond
self.current_song_time += .124 # Add 1.24 deciseconds
# compensatation .24
self.current_progress.set(str('%.1f' % self.current_song_time) + \
" seconds of: " + str(self.DurationSecs))
root.update() # Process other events
root.after(100) # Sleep 1 decisecond
The problem with this band-aid fix is it is highly machine dependent. My machine is a Skylake for example. Also it is highly dependent on what other processes are running at the same time. When testing my machine load was relatively light:
How can I programmatically account for lost time in order to increment elapsed time accurately?
Perhaps there is a better way of simply querying ffplay
to find out song progress?
As an aside (I know it's frowned upon to ask two questions at once) why can't I simply check if PID
is null? I have tried .rstrip()
and .strip()
after .read()
to no avail with checking PID
equal to ""
or None
. If ffplay
every has a process ID under 10
program will misbehave.
You can use
subprocess.Popen()
to executeffplay
and redirectstderr
to PIPE, then you can read the progress fromstderr
and update the progress label.Below is an example: