xiph / rav1e

The fastest and safest AV1 encoder.
BSD 2-Clause "Simplified" License
3.72k stars 253 forks source link

Progress tracking, abort/timeout #2763

Open kornelski opened 3 years ago

kornelski commented 3 years ago

Encoding of AVIF images can take multiple seconds. Large images + slower settings even take a minute (#2750).

Currently rav1e has no way to report any progress of encoding an intra frame (how much of the frame been processed so far, allowing to estimate how long it will take).

There's no way to abort encoding while a frame is being encoded. This means that GUI applications can't cancel encoding when user cancels the operation (other than letting rav1e continue to run in background, eating CPU for nothing).

I think this could be solved by supporting a callback function that receives some indicator of progress, and can return true/false whether to continue.

shssoichiro commented 3 years ago

I think the cancellation works properly if you compile without the signal_hook feature. Personally I've never been a fan of this feature, if I want to cancel I want it to cancel immediately, but it was added as the default setting to allow clean exiting with a "playable" clip of what's been encoded so far.

As for progress within a single frame, this is a bit hard to measure because we don't know ahead of time how the partitions within a frame will be broken down, etc. I suppose it would be possible to show an estimation based on what phase of encoding we're in.

kornelski commented 3 years ago

AVIF encoding has quite different characteristics than video encoding. The signal_hook feature is unsuitable, because it is checked once per frame, but AVIF is a single frame.

I think encode_tile would have been a good place to report progress. It has a loop over sb_height, sb_width which can be used as a progress, and could check before every encode_partition_{topdown,bottomup} call.

lu-zero commented 3 years ago

signal_hook is a cli feature, we can add a progress/cancellation callback easily.

We just need to figure how much information do we want to pass to it.

trait Callback {
  fn progress(&mut self) -> bool;
}

or:

trait Callback {
  fn progress(&mut self, info: Info) -> bool;
}

I'd add the latter with an Info {} for now.

Would that work for you? What would you'd like to have as info?

kornelski commented 3 years ago

Yes, that would work for me.

I suggest info &Info so that it doesn't have to be Copy.

Aborting is most important, so empty Info is fine for now.

I would like to have some progress display, so percent_done: f32 would be nice. The percentage may be coarse and approximate.

lu-zero commented 3 years ago

Progress would just know a block got encoded, potentially which one and what are the total blocks in the frame, but not how many blocks since it could be called from different threads.