proxy: isolate proxies from export renders and improve proxy workflow

- FootageJob::should_use_proxy() centralizes the proxy decision; worker
  pre-decode now honors the render mode so exports always decode the
  original media (previously every frame was pre-decoded from proxies)
- global Tools > Use Proxy Media toggle with footage invalidation
- ffmpeg -progress parsing for real percentage feedback while generating
- divider mode (1/2, 1/4, 1/8 of source resolution) with UI, proxy
  filename tags and per-footage persistence (pdivider)
- Media Offline warning slat rendered for missing footage
- regression tests: export isolation, relink invalidation, offline slat,
  progress parsing, divider arguments
This commit is contained in:
2026-07-19 21:43:58 +08:00
parent bb40b4923e
commit 0c02ff0d77
21 changed files with 494 additions and 25 deletions
+8 -5
View File
@@ -137,16 +137,18 @@ DecoderPtr resolve_decoder_from_cache(DecoderCache *decoder_cache,
}
FramePtr decode_input_frame(DecoderCache *decoder_cache,
const FootageInput &input, CancelAtom *cancel)
const FootageInput &input, CancelAtom *cancel,
RenderMode::Mode mode)
{
VideoParams stream_data = input.job.video_params();
QString filename = input.job.filename();
QString decoder_id = input.job.decoder();
int stream_index = stream_data.stream_index();
// Use generated proxy if one is attached to the job. The Footage node only
// attaches a proxy when it is enabled, ready, and matches this stream.
if (input.job.has_proxy()) {
// Use the generated proxy when this render is allowed to (preview only,
// never export). The Footage node only attaches a proxy when it is
// enabled, ready, and matches this stream.
if (input.job.should_use_proxy(mode)) {
filename = input.job.proxy_filename();
decoder_id = input.job.proxy_decoder();
stream_index = input.job.proxy_stream_index();
@@ -219,7 +221,8 @@ bool decode_input_frames(DecoderCache *decoder_cache,
return false;
}
FramePtr frame = decode_input_frame(decoder_cache, input, cancel);
FramePtr frame =
decode_input_frame(decoder_cache, input, cancel, params.mode);
if (!frame || !frame->is_allocated()) {
frames->clear();
return false;