YaLTeR / vapoursynth-rs

A safe Rust wrapper for VapourSynth.
Apache License 2.0
31 stars 8 forks source link

How do I invoke a plugin's function? #27

Closed SuspiciousDuck closed 1 month ago

SuspiciousDuck commented 1 month ago

I was trying to call a function from a plugin, but there's no constructor for the vapoursynth::map::Map type, so I can't create the arguments I need for the function.

quietvoid commented 1 month ago

You can create a OwnedMap.

See example: https://github.com/quietvoid/vspreview-rs/blob/main/src/vs_handler/mod.rs#L154

SuspiciousDuck commented 1 month ago

Thank you. I would appreciate it if it was mentioned in the documentation.

SuspiciousDuck commented 1 month ago

I was trying to call a vapoursynth plugin in order to get a list of quality scores, however, it appears that the keys of the invoked function are incorrect. I also wasn't able to get LSMASHSource nor resize working without creating an Environment from a string which just invoked LSMASHSource. What am I getting wrong?

let api = API::get().unwrap();
let core = api.create_core(12);
let vszip = core.get_plugin_by_namespace("vszip").unwrap().unwrap();
// ...
let mut args = OwnedMap::new(api);
// for `source` and `distorted`, i got the output from an Environment made with from_script, because i was having trouble getting the return value from LSMASHSource
args.set_node("reference", &source).unwrap(); 
args.set_node("distorted", &distorted).unwrap();
args.set_int("mode", 0).unwrap();
let scored = vszip.invoke("Metrics", &args).unwrap();
if scored.error().is_some() {
    panic!("{}", scored.error().unwrap()); // errors if you didnt set 8 bit color depth with `resize` (which i also had trouble getting the return value)
}
// when looping through the Keys, i found that the only Key was "clip"
let func = scored.get_function("frames").unwrap(); // this throws a KeyNotFound error
// ...

This is the python code I'm trying to recreate

scored = core.vszip.Metrics(src, dis, mode=0)
scores = []
total_frames = src.num_frames
with tqdm(total=total_frames, desc=f'Calculating SSIMULACRA 2 Scores for Q{quantizer}') as pbar:
    for (index, frame) in enumerate(scored.frames()):
        scores.append([index, frame.props['_SSIMULACRA2']])
        pbar.update(1)
quietvoid commented 1 month ago

frames() in Python is just a helper function and you can see its code here: https://github.com/vapoursynth/vapoursynth/blob/master/src/cython/vapoursynth.pyx#L1968

You can either iterate over the frames using scored.get_frame or scored.get_frame_async. And access the props using FrameRef.props().

SuspiciousDuck commented 1 month ago

Thanks! It's all working properly now.