mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-10 18:31:30 -06:00
Report offline footage and recover automatically when media returns (#3161)
* 3118: report and recover offline footage consistently * 3118: preserve manual reload and refresh data watch paths * 3118: document availability and reload contracts
This commit is contained in:
@@ -1004,6 +1004,11 @@ pub fn footage_salt_with(project: &effectcraft_project::Project, virtual_id: Opt
|
||||
hash_debug(&mut h, f);
|
||||
footage_stamp(&mut h, f, virtual_id);
|
||||
}
|
||||
if let Some(proxy) = it.proxy.as_ref().filter(|p| p.enabled) {
|
||||
h.write_u64(id.0);
|
||||
hash_debug(&mut h, proxy);
|
||||
footage_stamp(&mut h, &proxy.footage, virtual_id);
|
||||
}
|
||||
}
|
||||
let v = h.finish();
|
||||
(v as u64) ^ ((v >> 64) as u64)
|
||||
|
||||
@@ -99,20 +99,38 @@ pub trait FootageSource: Send + Sync {
|
||||
fn problem(&self, _footage: &Footage) -> Option<String> {
|
||||
None
|
||||
}
|
||||
/// [`Self::problem`] of what `item` shows: its proxy's while Use Proxy shows the proxy
|
||||
/// Missing files and [`Self::problem`] of what `item` shows: its proxy's while Use Proxy shows the proxy
|
||||
/// instead (the reason then says it is the proxy's), else the footage item's own. A
|
||||
/// composition has one only through its proxy.
|
||||
fn item_problem(&self, item: &effectcraft_project::Item) -> Option<String> {
|
||||
match item.proxy.as_deref().filter(|px| px.enabled && px.footage.has_video) {
|
||||
Some(px) => self.problem(&px.footage).map(|why| format!("Proxy: {why}")),
|
||||
Some(px) => {
|
||||
missing_problem(&px.footage, "Use Set Proxy to locate the proxy file.").or_else(|| self.problem(&px.footage)).map(|why| format!("Proxy: {why}"))
|
||||
}
|
||||
None => match &item.kind {
|
||||
ItemKind::Footage(f) => self.problem(f),
|
||||
ItemKind::Footage(f) => missing_problem(f, "Use File ▸ Dependencies ▸ Relink Missing Footage or Replace Footage.").or_else(|| self.problem(f)),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A known offline source, without filesystem access while painting or querying.
|
||||
fn missing_problem(f: &Footage, remedy: &str) -> Option<String> {
|
||||
(f.missing && !f.path.is_empty() && f.kind != effectcraft_project::FootageKind::Data).then(|| format!("Missing footage: {}. {remedy}", f.path))
|
||||
}
|
||||
|
||||
/// Inventory warning, including an unused proxy or an original currently replaced by a proxy.
|
||||
/// Viewer warnings instead use `item_problem`, which follows the active render source.
|
||||
pub fn missing_item_problem(item: &effectcraft_project::Item) -> Option<String> {
|
||||
if let ItemKind::Footage(f) = &item.kind
|
||||
&& let Some(why) = missing_problem(f, "Use File ▸ Dependencies ▸ Relink Missing Footage or Replace Footage.")
|
||||
{
|
||||
return Some(why);
|
||||
}
|
||||
item.proxy.as_ref().and_then(|p| missing_problem(&p.footage, "Use Set Proxy to locate the proxy file.")).map(|why| format!("Proxy: {why}"))
|
||||
}
|
||||
|
||||
/// A render's view of a [`FootageSource`] whose frame reads can be called off with `cancel`
|
||||
/// (a viewer frame nobody waits for any more, #329). Every read goes through
|
||||
/// [`FootageSource::cancellable`] on its own, so reads made for this render on another thread
|
||||
|
||||
@@ -46,7 +46,7 @@ mod opts;
|
||||
mod pipeline;
|
||||
|
||||
pub use accel::{Accelerator, Backend, FxStep, FxTarget};
|
||||
pub use footage::{CancellableFootage, FloatCurve, FootageSource, NoFootage, is_vector_footage};
|
||||
pub use footage::{CancellableFootage, FloatCurve, FootageSource, NoFootage, is_vector_footage, missing_item_problem};
|
||||
pub use frames::{
|
||||
adaptive_samples, blend_frames, cineon_frame, content_bounds, extended_region, field_frame, frame_position, frame_size, interpret_pixels, kurbo_path,
|
||||
render_frame, roi_inside,
|
||||
|
||||
Reference in New Issue
Block a user