mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-12 21:32:52 +00:00
#3534: footage going offline no longer drops saved analyses
Whether a footage file is there is an observation (footage.check sets Footage::missing without an edit), not part of the footage. The signature leaves it out, and keys saved by 0.22-0.24, which hashed it, are recognised with the file either online or offline. Warp Stabilizer, 3D Camera Tracker and Roto Brush analyses are kept through the next edit while the footage is offline and after it comes back.
This commit is contained in:
3 files changed
+51
-9
No files matched your search
@@ -226,7 +226,9 @@ impl Text {
|
||||
premul_color,
|
||||
loop_count,
|
||||
codec,
|
||||
missing,
|
||||
// Whether the file is there is an observation (`footage.check`), not an edit: an
|
||||
// offline file is the same footage, and its analyses stay valid (#3534).
|
||||
missing: _,
|
||||
sequence,
|
||||
color_profile,
|
||||
layer,
|
||||
@@ -276,7 +278,6 @@ impl Text {
|
||||
self.floats("matte", premul_color);
|
||||
self.field("loop", loop_count);
|
||||
self.str("codec", codec);
|
||||
self.field("missing", missing);
|
||||
self.field("frames", sequence.len());
|
||||
for s in sequence {
|
||||
self.str("file", s);
|
||||
|
||||
@@ -6,16 +6,19 @@ use effectcraft_project::{Footage, ItemId, ItemKind, Layer, LayerSource, Project
|
||||
|
||||
use super::fnv;
|
||||
|
||||
/// The signatures a saved key of `layer` may have been made from. Before `Footage::placed_page`
|
||||
/// was added in 0.23, the footage text ended without that field.
|
||||
/// The signatures a saved key of `layer` may have been made from. The footage's availability is
|
||||
/// tried both ways: those releases hashed it, though it isn't part of the footage (#3534). Before
|
||||
/// `Footage::placed_page` was added in 0.23, the footage text ended without that field.
|
||||
pub(crate) fn signatures(p: &Project, comp: ItemId, layer: &Layer) -> Vec<String> {
|
||||
let src = match &layer.source {
|
||||
LayerSource::Footage { item } | LayerSource::Solid { item } | LayerSource::Comp { item } => match p.item(*item).map(|i| &i.kind) {
|
||||
Some(ItemKind::Footage(f)) => {
|
||||
let mut out = Vec::with_capacity(2);
|
||||
out.push(signature_with_source(p, comp, layer, &footage_text(f, f.missing, true)));
|
||||
if matches!(layer.source, LayerSource::Footage { .. }) && !f.placed_page {
|
||||
out.push(signature_with_source(p, comp, layer, &footage_text(f, f.missing, false)));
|
||||
let mut out = Vec::with_capacity(4);
|
||||
for missing in [false, true] {
|
||||
out.push(signature_with_source(p, comp, layer, &footage_text(f, missing, true)));
|
||||
if matches!(layer.source, LayerSource::Footage { .. }) && !f.placed_page {
|
||||
out.push(signature_with_source(p, comp, layer, &footage_text(f, missing, false)));
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ fn analyses_saved_by_0_24_survive_edits_that_keep_their_frames() {
|
||||
fn signature_text_is_pinned() {
|
||||
let s = open(ANALYSED_0_24);
|
||||
let layer = s.project.comp(COMP).unwrap().layer(CLIP).unwrap();
|
||||
let key = r#"frames/1;footage=1;footage;path="/tmp/effectcraft-3456-shake.mp4";kind=video;w=160;h=120;par=1.0;rate=12/1;nativeRate=none;duration=254016000000;video=true;audio=false;alpha=ignore;matte=[0.0, 0.0, 0.0];loop=1;codec="H.264 (High)";missing=false;frames=0;profile{rec709;};layer=none;fields=off;invertAlpha=false;linearLight=false;preserveRgb=false;cineon;log=false;points=[0.0, 1023.0, 95.0, 685.0, 1.7, 20.0];units=10bit;data=none;page=0;alphabetical=false;startTimecode=none;fileTimecode=none;placedPage=false;in=0;out=254016000000;start=0;stretch=100.0;timeRemap{prop="timeRemap";scalar=0.0;spatial=false;key=0;scalar=0.2;interp=linear/linear;continuous=false;autoBezier=false;spatialIn=[0.0, 0.0, 0.0];spatialOut=[0.0, 0.0, 0.0];spatialAuto=true;spatialContinuous=false;roving=false;muted=false;key=254016000000;scalar=1.0;interp=linear/linear;continuous=false;autoBezier=false;spatialIn=[0.0, 0.0, 0.0];spatialOut=[0.0, 0.0, 0.0];spatialAuto=true;spatialContinuous=false;roving=false;muted=false;expr=none;};compRate{rate=12/1;};"#;
|
||||
let key = r#"frames/1;footage=1;footage;path="/tmp/effectcraft-3456-shake.mp4";kind=video;w=160;h=120;par=1.0;rate=12/1;nativeRate=none;duration=254016000000;video=true;audio=false;alpha=ignore;matte=[0.0, 0.0, 0.0];loop=1;codec="H.264 (High)";frames=0;profile{rec709;};layer=none;fields=off;invertAlpha=false;linearLight=false;preserveRgb=false;cineon;log=false;points=[0.0, 1023.0, 95.0, 685.0, 1.7, 20.0];units=10bit;data=none;page=0;alphabetical=false;startTimecode=none;fileTimecode=none;placedPage=false;in=0;out=254016000000;start=0;stretch=100.0;timeRemap{prop="timeRemap";scalar=0.0;spatial=false;key=0;scalar=0.2;interp=linear/linear;continuous=false;autoBezier=false;spatialIn=[0.0, 0.0, 0.0];spatialOut=[0.0, 0.0, 0.0];spatialAuto=true;spatialContinuous=false;roving=false;muted=false;key=254016000000;scalar=1.0;interp=linear/linear;continuous=false;autoBezier=false;spatialIn=[0.0, 0.0, 0.0];spatialOut=[0.0, 0.0, 0.0];spatialAuto=true;spatialContinuous=false;roving=false;muted=false;expr=none;};compRate{rate=12/1;};"#;
|
||||
assert_eq!(crate::analysis::frames_key::signature_text(&s.project, COMP, layer), key);
|
||||
}
|
||||
|
||||
@@ -143,6 +143,14 @@ fn todays_keys_survive_edits_that_keep_their_frames() {
|
||||
let mut s = open(&s.project.to_json());
|
||||
add_to_render_queue(&mut s);
|
||||
assert_eq!(saved(&s), before);
|
||||
// Offline and back online (#3534).
|
||||
for missing in [true, false] {
|
||||
if let Some(effectcraft_project::ItemKind::Footage(f)) = std::sync::Arc::make_mut(&mut s.project).item_mut(ItemId(1)).map(|i| &mut i.kind) {
|
||||
f.missing = missing;
|
||||
}
|
||||
add_to_render_queue(&mut s);
|
||||
assert_eq!(saved(&s), before);
|
||||
}
|
||||
// Names and labels only show things.
|
||||
s.execute_checked("layer.rename", json!({"layer": CLIP.0, "name": "Renamed"})).unwrap();
|
||||
s.edit("rename", None, |p, _| {
|
||||
@@ -160,3 +168,33 @@ fn todays_keys_survive_edits_that_keep_their_frames() {
|
||||
s.execute_checked("file.interpretFootage", json!({"items": [1], "invertAlpha": true})).unwrap();
|
||||
assert!(saved(&s).iter().all(|(data, _)| data.is_empty()));
|
||||
}
|
||||
|
||||
/// Footage going offline (or coming back) is an observation, not an edit: the next edit keeps
|
||||
/// every analysis (#3534).
|
||||
#[test]
|
||||
fn offline_footage_keeps_analyses() {
|
||||
let mut s = open(ANALYSED_0_24);
|
||||
let before = saved(&s);
|
||||
let missing = |s: &Session| matches!(&s.project.item(ItemId(1)).unwrap().kind, effectcraft_project::ItemKind::Footage(f) if f.missing);
|
||||
// The fixture's footage path doesn't exist here: the check marks it missing.
|
||||
let r = s.execute_checked("footage.check", json!({"wait": true})).unwrap();
|
||||
assert_eq!(r["missing"], 1, "{r}");
|
||||
assert!(missing(&s));
|
||||
add_to_render_queue(&mut s);
|
||||
assert_eq!(saved(&s), before);
|
||||
|
||||
// Saved and reopened while offline, then back online.
|
||||
let mut s = open(&s.project.to_json());
|
||||
assert!(missing(&s));
|
||||
add_to_render_queue(&mut s);
|
||||
assert_eq!(saved(&s), before);
|
||||
if let Some(effectcraft_project::ItemKind::Footage(f)) = std::sync::Arc::make_mut(&mut s.project).item_mut(ItemId(1)).map(|i| &mut i.kind) {
|
||||
f.missing = false;
|
||||
}
|
||||
add_to_render_queue(&mut s);
|
||||
assert_eq!(saved(&s), before);
|
||||
|
||||
// A real change while offline still clears them.
|
||||
s.execute_checked("file.interpretFootage", json!({"items": [1], "invertAlpha": true})).unwrap();
|
||||
assert!(saved(&s).iter().all(|(data, _)| data.is_empty()));
|
||||
}
|
||||
Reference in new issue
Block a user