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).
This commit is contained in:
2026-09-01 21:33:12 +08:00
parent 45c288ce97
commit 7065fb0108
+28 -2
View File
@@ -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(