mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-30 04:57:54 -06:00
#886: say why footage the decoders can't read shows no picture
Problem: a movie whose profile the software decoders lack (H.264 High 4:2:2 / 10-bit) probes fine, then every frame read fails; MediaPool logged the error per frame and returned None, so the layer rendered black with no sign why in the viewer, Project panel or for agents. Fix: MediaPool records the reason once per file (codec from the probe plus the decoder's text without error wrappers; I/O errors stay with missing-footage handling), logs it once, and exposes it through the new FootageSource::problem. The Composition viewer shows it on the affected layer, the Project panel marks the item with a warning whose tooltip is the reason, and project.summary / footage.info carry a "problem" field. Cleared when the file is forgotten; only set when decoding really failed, so a hardware decoder that handles the file shows nothing. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
67434e9038
commit
74b95b0a9d
@@ -206,8 +206,12 @@ fn info(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
let item = s.project.item(v.item);
|
||||
let name = item.map(|i| i.name.clone()).unwrap_or_default();
|
||||
let frame = fr.frame_at(v.time);
|
||||
let problem = match item.map(|i| &i.kind) {
|
||||
Some(ItemKind::Footage(f)) => s.footage.problem(f),
|
||||
_ => None,
|
||||
};
|
||||
Ok(
|
||||
json!({"item": v.item.0, "name": name, "time": v.time.seconds(), "frame": frame, "timecode": timecode(item, fr, frame), "in": v.in_point.map(|t| t.seconds()), "out": v.out_point.map(|t| t.seconds()), "duration": dur.map(|d| d.seconds()), "frameRate": fr.as_f64()}),
|
||||
json!({"item": v.item.0, "name": name, "time": v.time.seconds(), "frame": frame, "timecode": timecode(item, fr, frame), "in": v.in_point.map(|t| t.seconds()), "out": v.out_point.map(|t| t.seconds()), "duration": dur.map(|d| d.seconds()), "frameRate": fr.as_f64(), "problem": problem}),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,13 @@ fn summary(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
o["layers"] = json!(c.layers.len());
|
||||
o["frameRate"] = json!(c.frame_rate.as_f64());
|
||||
}
|
||||
// Footage that shows no picture although its file is there (a codec or profile the
|
||||
// decoders lack): why, so an agent can tell the user.
|
||||
if let ItemKind::Footage(f) = &i.kind
|
||||
&& let Some(why) = s.footage.problem(f)
|
||||
{
|
||||
o["problem"] = json!(why);
|
||||
}
|
||||
o
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -629,3 +629,36 @@ fn media_browser_over_a_virtual_tree() {
|
||||
assert_eq!(*b.actions.lock().unwrap(), ["openFolder"]);
|
||||
assert!(s.execute("mediaBrowser.action", json!({})).is_err());
|
||||
}
|
||||
|
||||
/// Footage the source can't decode is reported with its reason by `project.summary` and
|
||||
/// `footage.info`, so an agent can tell the user why the picture is black.
|
||||
#[test]
|
||||
fn footage_that_cannot_be_decoded_reports_why() {
|
||||
struct Broken;
|
||||
impl FootageSource for Broken {
|
||||
fn frame(&self, _: ItemId, _: &Footage, _: Tick) -> Option<Arc<Image>> {
|
||||
None
|
||||
}
|
||||
fn problem(&self, f: &Footage) -> Option<String> {
|
||||
Some(format!("{} isn't supported by the built-in decoder", f.codec))
|
||||
}
|
||||
}
|
||||
let mut s = Session { footage: Arc::new(Broken), ..Default::default() };
|
||||
s.execute("comp.new", json!({"name": "C", "width": 64, "height": 36, "duration": 2})).unwrap();
|
||||
let f = Footage {
|
||||
kind: FootageKind::Video,
|
||||
path: "a.mp4".into(),
|
||||
codec: "H.264 (High 4:2:2)".into(),
|
||||
width: 64,
|
||||
height: 36,
|
||||
has_video: true,
|
||||
..Default::default()
|
||||
};
|
||||
let item = std::sync::Arc::make_mut(&mut s.project).add_item("Clip", Default::default(), None, ItemKind::Footage(f));
|
||||
let sum = s.execute("project.summary", json!({})).unwrap();
|
||||
let it = sum["items"].as_array().unwrap().iter().find(|i| i["id"] == json!(item.0)).unwrap();
|
||||
assert_eq!(it["problem"], json!("H.264 (High 4:2:2) isn't supported by the built-in decoder"));
|
||||
assert!(sum["items"].as_array().unwrap().iter().filter(|i| i["id"] != json!(item.0)).all(|i| i.get("problem").is_none()), "only footage reports one");
|
||||
s.execute("footage.open", json!({"item": item.0})).unwrap();
|
||||
assert_eq!(s.execute("footage.info", json!({})).unwrap()["problem"], it["problem"]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user