You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Overall render progress omits the post-process stage, freezing the rate and the time estimate #23
Segmentation fills 0 → N, Encode resumes at N and runs to 2N, and Post-process
reports nothing. The overall counter therefore stands still for the entire
Post-process stage, and because the dialog derives the frame rate and the
remaining time from that counter, both freeze with it.
Observed
A 60 s clip at the default 15 fps output, so N = 900 and the dialog shows a
total of 1800. Same run, three moments:
elapsed
stage
stage frame
overall
shown rate
shown remaining
23:56
Post-process
425 / 900
900 / 1800
0.6 fps
23:47
25:08
Post-process
807 / 900
900 / 1800
0.6 fps
23:47
26:04
Encode
15 / 900
915 / 1800
1.0 fps
14:39
Between the first two rows, 382 frames completed in 72 s — about 5.3 frames/s —
while the dialog reported 0.6 fps and an unchanged 23:47. The remaining time was
identical to the second, 72 seconds apart: it is not merely inaccurate, it stops
being recomputed. Actual time left at that point was roughly 18 seconds against
24 minutes displayed, a factor of about 80.
The third row shows the counter resuming in Encode, and the rate becoming
plausible again — the display is correct whenever the counter moves, and blind
exactly while Post-process runs.
Why it matters beyond cosmetics
The bar reads half done when two thirds of the work remains.
For one whole stage the estimate stands still at a value far above the truth.
A user watching "23:47 remaining" not move for minutes has good reason to
press Cancel on a render that is seconds from finishing.
The whole run took roughly 25.5 minutes; the dialog spent about six of those
claiming twenty-four were left.
Environment
Windows 11 26200, main at 22b77be plus #20's branch for the DirectML
runtime, BiRefNet Portrait on DmlExecutionProvider (Radeon RX 7900 XT).
The stage timings differ with hardware; the counter arithmetic does not.
Note
len(timestamps) * 2 appears twice and is the whole defect, but the fix is a
design choice rather than a constant: the three stages run at very different
rates here (roughly 0.7, 5.3 and ~1 frames/s), so counting them as equal units
would still produce a poor estimate even once Post-process is included.
Weighting them, or estimating per stage, would report honestly.
Taking this one; branch fix/overall-progress-stages.
Your closing note is right that the fix is a choice rather than a constant, and #27 landing since you filed this makes the choice narrower than it looked.
The rebuild path has the same defect, worse._encode_snapshot is now reached from two callers and already carries a rebuilt flag. rebuild() sets no overall context at all, so the counter is empty through the whole post-process stage and the encode stage then starts a fresh 0..frame_count scale — the bar jumps from nothing to a new maximum mid-job. Since the transform stage exists to make the cheap re-encode the normal path, that is now the progress users will see most often.
Trimming makes the stages different lengths. The per-frame post-process loop moved to transform_stage.stage_encoder_frames, which stages only transform.kept_range(frame_count). After a trim, segmentation runs over the full timestamp grid while post-process and encode run over the kept frames only. So no single multiplier on one frame count is correct, independently of whether it is two or three.
The exact freeze is one line short of where the constant is: that loop calls context.progress("Framing", …) with no overall_completed/overall_total, so it publishes stage progress while leaving the overall figure untouched.
What I am implementing:
Case
Budget
Full render
timestamps + 2 × kept — segmentation, then post-process, then encode
Transform rebuild
2 × kept — post-process, then encode
Auto-fit (max_bytes)
encode stays indeterminate exactly as today; the earlier stages report their real share
Deliberately not doing the weighted or per-stage-rate estimate you raised. The measured defect is a counter that stops and an estimate that stops being recomputed, and honest unit counting fixes both; the stages having different rates makes the estimate imprecise, which is a smaller and separate problem. If it still reads badly on a real run with the rates you measured (0.7 / 5.3 / ~1 fps), that is worth its own issue with the numbers from the fixed build.
Tests cover all four shapes including a trimmed render.
Activity
smb commentedon Sep 4, 2026
Taking this one; branch
fix/overall-progress-stages.Your closing note is right that the fix is a choice rather than a constant, and #27 landing since you filed this makes the choice narrower than it looked.
The rebuild path has the same defect, worse.
_encode_snapshotis now reached from two callers and already carries arebuiltflag.rebuild()sets no overall context at all, so the counter is empty through the whole post-process stage and the encode stage then starts a fresh0..frame_countscale — the bar jumps from nothing to a new maximum mid-job. Since the transform stage exists to make the cheap re-encode the normal path, that is now the progress users will see most often.Trimming makes the stages different lengths. The per-frame post-process loop moved to
transform_stage.stage_encoder_frames, which stages onlytransform.kept_range(frame_count). After a trim, segmentation runs over the full timestamp grid while post-process and encode run over the kept frames only. So no single multiplier on one frame count is correct, independently of whether it is two or three.The exact freeze is one line short of where the constant is: that loop calls
context.progress("Framing", …)with nooverall_completed/overall_total, so it publishes stage progress while leaving the overall figure untouched.What I am implementing:
timestamps + 2 × kept— segmentation, then post-process, then encode2 × kept— post-process, then encodemax_bytes)Deliberately not doing the weighted or per-stage-rate estimate you raised. The measured defect is a counter that stops and an estimate that stops being recomputed, and honest unit counting fixes both; the stages having different rates makes the estimate imprecise, which is a smaller and separate problem. If it still reads badly on a real run with the rates you measured (0.7 / 5.3 / ~1 fps), that is worth its own issue with the numbers from the fixed build.
Tests cover all four shapes including a trimmed render.