From 7065fb0108388e4c089a73911c035dd8707bdc36 Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Tue, 1 Sep 2026 21:33:12 +0800 Subject: [PATCH] footage: node-graph decode uses a ready proxy, tolerate unset stream index Re-applies the proxy selection (with the -1 tolerance) after the revert: the node-graph viewer decode must stand in a ready proxy for the 4K original, and a proxy generated before the stream-index recording (index -1) still matches the first video stream rather than silently falling back to the 4K source (the 'main viewer got stuck' report). --- crates/oak-node/src/footage.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/crates/oak-node/src/footage.rs b/crates/oak-node/src/footage.rs index 6b2971f83..c00dd6134 100644 --- a/crates/oak-node/src/footage.rs +++ b/crates/oak-node/src/footage.rs @@ -25,6 +25,13 @@ use crate::input::Input; use crate::node::{Category, NodeBehavior, NodeCore}; use crate::value::{AudioParams, NodeValue, NodeValueRow, NodeValueTable, ValueType, VideoParams}; +/// Whether the footage's proxy state value means "the proxy file is +/// ready on disk" (the C++ `ProxyState::Ready` = 2; the footage behavior +/// stores it raw to avoid a codec-crate dependency here). +pub(crate) fn proxymanager_proxy_state_ready(state: i32) -> bool { + state == 2 +} + /// One media stream inside a footage file. #[derive(Clone, Debug)] pub struct StreamInfo { @@ -364,9 +371,28 @@ impl NodeBehavior for FootageBehavior { let Some(stream) = self.streams.iter().find(|s| s.is_video) else { return; }; + // Proxy selection mirrors the montage path's + // `preview_footage_media`: enabled + Ready state, and the proxy + // replaces the first video stream only (C++ matches the proxy's + // video stream index against the footage's first video stream). + // `proxy_video_stream_index == -1` (a proxy generated before the + // stream index was recorded) still matches the FIRST video stream + // — a strict equality would silently disable the proxy and decode + // the 4K original again (the "preview stopped moving" report). + let proxy_ready = proxymanager_proxy_state_ready(self.proxy_state); + let use_proxy = self.proxy_enabled + && !self.proxy.is_empty() + && proxy_ready + && (self.proxy_video_stream_index == stream.index + || self.proxy_video_stream_index < 0); + let (filename, stream_index) = if use_proxy { + (self.proxy.clone(), 0) + } else { + (self.filename.clone(), stream.index) + }; let payload = crate::nodes::jobs::FootageJobPayload { - filename: self.filename.clone(), - stream_index: stream.index, + filename, + stream_index, time, }; table.push(