Skip to content

Show a more fine grained progress bar #3597

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

Merged
merged 11 commits into from
Oct 19, 2020
63 changes: 41 additions & 22 deletions src/windows/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import os
import time
import tempfile
import math

import openshot

Expand Down Expand Up @@ -314,10 +315,10 @@ def getProfileName(self, profile_path):
if profile_path == path:
return profile

def updateProgressBar(self, title_message, start_frame, end_frame, current_frame):
def updateProgressBar(self, title_message, start_frame, end_frame, current_frame, progress_format):
"""Update progress bar during exporting"""
if end_frame - start_frame > 0:
percentage_string = "%4.1f%% " % (( current_frame - start_frame ) / ( end_frame - start_frame ) * 100)
percentage_string = progress_format % (( current_frame - start_frame ) / ( end_frame - start_frame ) * 100)
else:
percentage_string = "100%"
self.progressExportVideo.setValue(current_frame)
Expand Down Expand Up @@ -720,6 +721,17 @@ def enableControls(self):
def accept(self):
""" Start exporting video """

# Build the export window title
def titlestring(sec, fps, mess):
formatstr = "%(hours)d:%(minutes)02d:%(seconds)02d " + mess + " (%(fps)5.2f FPS)"
title_mes = _(formatstr) % {
'hours': sec / 3600,
'minutes': (sec / 60) % 60,
'seconds': sec % 60,
'fps': fps}
return title_mes


# get translations
_ = get_app()._tr

Expand Down Expand Up @@ -903,27 +915,42 @@ def accept(self):

progressstep = max(1 , round(( video_settings.get("end_frame") - video_settings.get("start_frame") ) / 1000))
start_time_export = time.time()
seconds_run = 0
start_frame_export = video_settings.get("start_frame")
end_frame_export = video_settings.get("end_frame")
last_exported_time = time.time()
old_part = 0.0
new_part = 0.0
afterpoint = 1
# Precision of the progress bar
progress_format = "%4.1f%% "
# Write each frame in the selected range
for frame in range(video_settings.get("start_frame"), video_settings.get("end_frame") + 1):
# Update progress bar (emit signal to main window)
if (frame % progressstep) == 0:
end_time_export = time.time()
end_time_export = time.time()
if ((frame % progressstep) == 0) or ((end_time_export - last_exported_time) > 1):
new_part = (frame - start_frame_export) * 1.0 / (end_frame_export - start_frame_export)
if ((new_part - old_part) > 0.0):
afterpoint = math.ceil( -2.0 - math.log10( new_part - old_part ))
else:
afterpoint = 1
if afterpoint < 1:
afterpoint = 1
if afterpoint > 5:
afterpoint = 5
Copy link
Contributor

@SuslikV SuslikV Jul 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What these "magical" numbers is about?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the number of digits after the decimal point. Here they are set to a minimum of 1 and a maximum of 5. One was the previous default value 4.1f .
More than 5 doesn't make sense as in total this would be a higher precision than 7 digits. At 60 fps and 86400 seconds a day that would be 5,184,000 frames per day.
I have more of a problem with the maximum time between updates; I think 1 second is too low. 2 or 5 seconds might be better.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm against if (x < 20) in the code when there is no comment why 20 was chosen here. Sometimes people like to make constants or variables that are much easier to modify later:

max_digits = 20; //max number of digits after the decimal point
if (x < max_digits) ...

Copy link
Collaborator Author

@eisneinechse eisneinechse Jul 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I will make a change to this PR soon adding comments.
Today I might not have the time, soon.
Maybe also explain the calculation with the log10

old_part = new_part
progress_format = "%4." + str(afterpoint) + "f%% "
last_exported_time = time.time()
if ((( frame - start_frame_export ) != 0) & (( end_time_export - start_time_export ) != 0)):
seconds_left = round(( start_time_export - end_time_export )*( frame - end_frame_export )/( frame - start_frame_export ))
fps_encode = ((frame - start_frame_export)/(end_time_export-start_time_export))
if frame == end_frame_export:
title_message = _("Finalizing video export, please wait...")
else:
title_message = _("%(hours)d:%(minutes)02d:%(seconds)02d Remaining (%(fps)5.2f FPS)") % {
'hours': seconds_left / 3600,
'minutes': (seconds_left / 60) % 60,
'seconds': seconds_left % 60,
'fps': fps_encode}
title_message = titlestring(seconds_left, fps_encode, "Remaining")

# Emit frame exported
get_app().window.ExportFrame.emit(title_message, video_settings.get("start_frame"), video_settings.get("end_frame"), frame)
get_app().window.ExportFrame.emit(title_message, video_settings.get("start_frame"), video_settings.get("end_frame"), frame, progress_format)

# Process events (to show the progress bar moving)
QCoreApplication.processEvents()
Expand All @@ -940,14 +967,10 @@ def accept(self):

# Emit final exported frame (with elapsed time)
seconds_run = round((end_time_export - start_time_export))
title_message = _("%(hours)d:%(minutes)02d:%(seconds)02d Elapsed (%(fps)5.2f FPS)") % {
'hours': seconds_run / 3600,
'minutes': (seconds_run / 60) % 60,
'seconds': seconds_run % 60,
'fps': fps_encode}
title_message = titlestring(seconds_run, fps_encode, "Elapsed")

get_app().window.ExportFrame.emit(title_message, video_settings.get("start_frame"),
video_settings.get("end_frame"), frame)
video_settings.get("end_frame"), frame, progress_format)

except Exception as e:
# TODO: Find a better way to catch the error. This is the only way I have found that
Expand Down Expand Up @@ -1012,14 +1035,10 @@ def accept(self):
self.close_button.setVisible(True)

# Restore windows title to show elapsed time
title_message = _("%(hours)d:%(minutes)02d:%(seconds)02d Elapsed (%(fps)5.2f FPS)") % {
'hours': seconds_run / 3600,
'minutes': (seconds_run / 60) % 60,
'seconds': seconds_run % 60,
'fps': fps_encode}
title_message = titlestring(seconds_run, fps_encode, "Elapsed")

get_app().window.ExportFrame.emit(title_message, video_settings.get("start_frame"),
video_settings.get("end_frame"), frame)
video_settings.get("end_frame"), frame, progress_format)

# Make progress bar green (to indicate we are done)
from PyQt5.QtGui import QPalette
Expand Down
2 changes: 1 addition & 1 deletion src/windows/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class MainWindow(QMainWindow, updates.UpdateWatcher):
WaveformReady = pyqtSignal(str, list)
TransformSignal = pyqtSignal(str)
ExportStarted = pyqtSignal(str, int, int)
ExportFrame = pyqtSignal(str, int, int, int)
ExportFrame = pyqtSignal(str, int, int, int, str)
ExportEnded = pyqtSignal(str)
MaxSizeChanged = pyqtSignal(object)
InsertKeyframe = pyqtSignal(object)
Expand Down