mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-12 21:32:52 +00:00
A fixture keyed by the current release: Warp Stabilizer, 3D Camera Tracker and Roto Brush keys keep matching through edits that keep the frames, undo and save/reopen, and real changes still clear them.
This commit is contained in:
5 files changed
+105
No files matched your search
@@ -133,6 +133,7 @@ configuration from these Apache-2.0 projects:
|
||||
|
||||
| Asset | Author | Source | Licence |
|
||||
|---|---|---|---|
|
||||
| `crates/engine/src/tests/fixtures/analysed-0.24.ecproj` | arnav-hiwarkar | Original work, synthetic project keyed by EffectCraft 0.24.1 | MIT OR Apache-2.0 |
|
||||
| `crates/engine/src/tests/fixtures/object-matte-0.22.ecproj` | lisn0 | Original work, synthetic project saved by EffectCraft 0.22.0 | MIT OR Apache-2.0 |
|
||||
| `crates/engine/src/tests/fixtures/tracked-0.22.ecproj` | arnav-hiwarkar | Original work, synthetic project saved by EffectCraft 0.22.0 | MIT OR Apache-2.0 |
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ mod key_metadata_order;
|
||||
mod key_time;
|
||||
mod keyframe_text;
|
||||
mod keylight;
|
||||
mod analysis_signature;
|
||||
mod legacy_analysis_keys;
|
||||
mod limits;
|
||||
mod lottie;
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
//! Warp Stabilizer, 3D Camera Tracker and Roto Brush keys saved by 0.24 keep matching their
|
||||
//! layer's frames after edits that don't change them, and a real change still clears them.
|
||||
|
||||
use effectcraft_effects::camera_tracker::{TRACKS, TRACKS_KEY};
|
||||
use effectcraft_effects::roto::{FROZEN, INPUT_KEY};
|
||||
use effectcraft_effects::warp_stab::{ANALYSIS, ANALYSIS_KEY};
|
||||
use effectcraft_keyframe::Value;
|
||||
use effectcraft_project::{ItemId, LayerId, Project};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::Session;
|
||||
|
||||
const COMP: ItemId = ItemId(2);
|
||||
const CLIP: LayerId = LayerId(3);
|
||||
const WARP: u64 = 26;
|
||||
const TRACKER: u64 = 54;
|
||||
const ROTO: u64 = 86;
|
||||
|
||||
/// Saved by 0.24.1 (before #3534/#3536): the clip of `tracked-0.22.ecproj` with Time Remap, a
|
||||
/// mask, a Gaussian Blur and a Roto Brush, its analyses replaced by short stand-ins. The keys
|
||||
/// are the ones that version computed for it.
|
||||
const ANALYSED_0_24: &str = include_str!("fixtures/analysed-0.24.ecproj");
|
||||
const SIGNATURE_0_24: &str = "03efb7c4b0f27b65";
|
||||
const ROTO_INPUT_0_24: &str = "7b319ce93027617c";
|
||||
|
||||
fn open(json: &str) -> Session {
|
||||
let mut s = Session::default();
|
||||
s.replace_project(Project::from_json(json).unwrap(), None);
|
||||
s.open_comp(COMP);
|
||||
s
|
||||
}
|
||||
|
||||
/// The (data, key) of the Warp Stabilizer, the 3D Camera Tracker and the Roto Brush.
|
||||
fn saved(s: &Session) -> [(String, String); 3] {
|
||||
let layer = s.project.comp(COMP).unwrap().layer(CLIP).unwrap();
|
||||
let get = |uid: u64, data: &str, key: &str| {
|
||||
let params = crate::camera_track::static_params(layer.props.find_group(uid).unwrap());
|
||||
let text = |id: &str| match params.get(id) {
|
||||
Some(Value::Str(s)) => s.clone(),
|
||||
other => panic!("{id}: {other:?}"),
|
||||
};
|
||||
(text(data), text(key))
|
||||
};
|
||||
[get(WARP, ANALYSIS, ANALYSIS_KEY), get(TRACKER, TRACKS, TRACKS_KEY), get(ROTO, FROZEN, INPUT_KEY)]
|
||||
}
|
||||
|
||||
fn add_to_render_queue(s: &mut Session) {
|
||||
s.execute_checked("renderQueue.add", json!({"comp": COMP.0, "format": "png", "output": "frame.png"})).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn analyses_saved_by_0_24_survive_edits_that_keep_their_frames() {
|
||||
let mut s = open(ANALYSED_0_24);
|
||||
let before = saved(&s);
|
||||
assert_eq!(before[0], ("saved analysis".into(), SIGNATURE_0_24.into()));
|
||||
assert_eq!(before[1], ("saved tracks".into(), SIGNATURE_0_24.into()));
|
||||
assert_eq!(before[2], ("saved frozen".into(), ROTO_INPUT_0_24.into()));
|
||||
|
||||
add_to_render_queue(&mut s);
|
||||
assert_eq!(saved(&s), before);
|
||||
s.execute_checked("edit.undo", json!({})).unwrap();
|
||||
assert_eq!(saved(&s), before);
|
||||
|
||||
// Saved and reopened, the keys still match.
|
||||
let mut s = open(&s.project.to_json());
|
||||
add_to_render_queue(&mut s);
|
||||
assert_eq!(saved(&s), before);
|
||||
|
||||
// Other frames: all three are cleared (the Roto Brush gets a new key), and undo brings them back.
|
||||
s.execute_checked("layer.timing", json!({"layer": CLIP.0, "out": 0.25})).unwrap();
|
||||
let after = saved(&s);
|
||||
assert_eq!(after[0], (String::new(), String::new()));
|
||||
assert_eq!(after[1], (String::new(), String::new()));
|
||||
assert_eq!(after[2].0, "");
|
||||
assert_ne!(after[2].1, ROTO_INPUT_0_24);
|
||||
s.execute_checked("edit.undo", json!({})).unwrap();
|
||||
assert_eq!(saved(&s), before);
|
||||
|
||||
// Time Remap is part of the frames.
|
||||
s.execute_checked("prop.set", json!({"layer": CLIP.0, "path": "timeRemap", "value": 0.3})).unwrap();
|
||||
assert!(saved(&s).iter().all(|(data, _)| data.is_empty()));
|
||||
s.execute_checked("edit.undo", json!({})).unwrap();
|
||||
|
||||
// The Roto Brush's input also has the layer's masks and the effects above it.
|
||||
s.execute_checked("prop.set", json!({"layer": CLIP.0, "path": "effects/#3/blurriness", "value": 4})).unwrap();
|
||||
let after = saved(&s);
|
||||
assert_eq!(after[2].0, "");
|
||||
assert_ne!(after[2].1, ROTO_INPUT_0_24);
|
||||
s.execute_checked("edit.undo", json!({})).unwrap();
|
||||
s.execute_checked("prop.set", json!({"layer": CLIP.0, "path": "masks/#1/expansion", "value": 3})).unwrap();
|
||||
assert_eq!(saved(&s)[2].0, "");
|
||||
s.execute_checked("edit.undo", json!({})).unwrap();
|
||||
assert_eq!(saved(&s), before);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"schema":2,"settings":{"bit_depth":"Bpc8","linearize":false,"working_space":null,"blend_linear":false,"time_display":"Timecode","frame_start":0,"audio_sample_rate":48000,"gpu_acceleration":true,"color_engine":"Adobe","hdr":"Clip","output_space":null,"working_gamma":2.2},"items":{"1":{"id":1,"name":"effectcraft-3456-shake.mp4","label":"Aqua","comment":"","parent":null,"kind":{"type":"Footage","path":"/tmp/effectcraft-3456-shake.mp4","kind":"Video","width":160,"height":120,"pixel_aspect":1.0,"frame_rate":{"num":12,"den":1},"native_rate":null,"duration":254016000000,"has_video":true,"has_audio":false,"alpha":"Ignore","premul_color":[0.0,0.0,0.0],"loop_count":1,"codec":"H.264 (High)","missing":false,"color_profile":"Rec709"}},"2":{"id":2,"name":"effectcraft-3456-shake","label":"Sandstone","comment":"","parent":null,"kind":{"type":"Comp","width":160,"height":120,"pixel_aspect":1.0,"frame_rate":{"num":12,"den":1},"duration":254016000000,"display_start":0,"background":[0.0,0.0,0.0],"work_area":[0,254016000000],"layers":[{"id":3,"name":"effectcraft-3456-shake.mp4","source":{"type":"Footage","item":1},"label":"Aqua","comment":"","start_time":0,"in_point":0,"out_point":254016000000,"stretch":100.0,"switches":{"video":true,"audio":true,"solo":false,"locked":false,"shy":false,"collapse":false,"quality":"Best","sampling":"Bilinear","effects":true,"frame_blend":"Off","motion_blur":false,"adjustment":false,"three_d":false,"guide":false},"blend_mode":"Normal","preserve_transparency":false,"track_matte":null,"parent":null,"markers":[],"auto_orient":"Off","props":{"uid":4,"match":"layer","name":"effectcraft-3456-shake.mp4","kind":{"kind":"Plain"},"enabled":true,"children":[{"node":"Prop","uid":76,"match":"timeRemap","name":"Time Remap","value":{"t":"Scalar","v":0.0},"keys":[{"time":0,"value":{"t":"Scalar","v":0.2},"in_interp":"Linear","out_interp":"Linear","in_ease":[],"out_ease":[],"continuous":false,"auto_bezier":false,"spatial_in":[0.0,0.0,0.0],"spatial_out":[0.0,0.0,0.0],"spatial_auto":true,"spatial_continuous":false,"roving":false},{"time":254016000000,"value":{"t":"Scalar","v":1.0},"in_interp":"Linear","out_interp":"Linear","in_ease":[],"out_ease":[],"continuous":false,"auto_bezier":false,"spatial_in":[0.0,0.0,0.0],"spatial_out":[0.0,0.0,0.0],"spatial_auto":true,"spatial_continuous":false,"roving":false}],"ui":{"kind":"Number"},"spatial":false,"hold_only":false,"three_d_only":false,"two_d_only":false,"shown_dims":0,"static_only":false},{"node":"Group","uid":5,"match":"masks","name":"Masks","kind":{"kind":"Plain"},"enabled":true,"children":[{"node":"Group","uid":77,"match":"mask","name":"Mask 1","kind":{"kind":"Mask","mode":"Add","inverted":false,"color":[177,180,79],"locked":false,"motion_blur":"SameAsLayer","feather_falloff":"Smooth","roto_bezier":false},"enabled":true,"children":[{"node":"Prop","uid":78,"match":"path","name":"Mask Path","value":{"t":"Path","v":{"vertices":[[10.0,10.0],[120.0,10.0],[120.0,100.0],[10.0,100.0]],"in_tangents":[[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0]],"out_tangents":[[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0]],"closed":false}},"ui":{"kind":"Path"},"spatial":false,"hold_only":false,"three_d_only":false,"two_d_only":false,"shown_dims":0,"static_only":false},{"node":"Prop","uid":79,"match":"feather","name":"Mask Feather","value":{"t":"Vec2","v":[0.0,0.0]},"ui":{"kind":"Pixels"},"spatial":false,"hold_only":false,"three_d_only":false,"two_d_only":false,"shown_dims":0,"static_only":false},{"node":"Prop","uid":80,"match":"opacity","name":"Mask Opacity","value":{"t":"Scalar","v":100.0},"ui":{"kind":"Slider","min":0.0,"max":100.0,"slider_min":0.0,"slider_max":100.0,"decimals":0},"spatial":false,"hold_only":false,"three_d_only":false,"two_d_only":false,"shown_dims":0,"static_only":false},{"node":"Prop","uid":81,"match":"expansion","name":"Mask Expansion","value":{"t":"Scalar","v":0.0},"ui":{"kind":"Pixels"},"spatial":false,"hold_only":false,"three_d_only":false,"two_d_only":false,"shown_dims":0,"static_only":false}]}]},{"node":"Group","uid":6,"match":"effects","name":"Effects","kind":{"kind":"Plain"},"enabled":true,"children":[{"node":"Group","uid":26,"match":"ec.distort.warpstabilizer","name":"Warp Stabilizer","kind":{"kind":"Effect","effect":"ec.distort.warpstabilizer"},"enabled":true,"children":[{"node":"Group","uid":28,"match":"stabilization","name":"Stabilization","kind":{"kind":"Plain"},"enabled":true,"children":[{"node":"Prop","uid":27,"match":"result","name":"Result","value":{"t":"Enum","v":0},"ui":{"kind":"Popup","options":["Smooth Motion","No Motion"]},"spatial":false,"hold_only":true,"three_d_only":false,"two_d_only":false,"shown_dims":0,"static_only":false},{"node":"Prop","uid":29,"match":"smoothness","name":"Smoothness","value":{"t":"Scalar","v":50.0},"ui":{"kind":"Slider","min":0.0,"max":1000.0,"slider_min":0.0,"slider_max":100.0,"decimals":0},"spatial":false,"hold_only":false,"three_d_only":false,"two_d_only":false,"shown_dims":0,"static_only":false},{"node":"Prop","uid":30,"match":"mLine truncated
|
||||
@@ -0,0 +1,8 @@
|
||||
asset: analysed-0.24.ecproj
|
||||
title: The tracked-0.22 clip with Time Remap, a mask, Gaussian Blur and Roto Brush, keyed by EffectCraft 0.24.1
|
||||
author: arnav-hiwarkar
|
||||
source: original work
|
||||
license: MIT OR Apache-2.0
|
||||
license-file: ../../../../../LICENSE-MIT
|
||||
added: 2026-11-12 by arnav-hiwarkar
|
||||
notes: Made from tracked-0.22.ecproj with 0.24.1 engine commands (enable Time Remap, a rectangle mask, Gaussian Blur and Roto Brush), its saved analyses replaced by short stand-in strings, and the Warp Stabilizer, 3D Camera Tracker and Roto Brush keys that 0.24.1 computed for it. Written as compact JSON. No media is needed: the tests only check that the keys are kept or cleared.
|
||||
Reference in new issue
Block a user