Giter Club home page Giter Club logo

after-effects's Introduction

after-effects

Current version: 0.1.6

High(er) level bindings for the Adobe AfterEffects® (Ae) SDK.

This wraps many of the API suites in the Ae SDK and exposes them in safe Rust.

This is WIP – only tested on macOS. Will likely require additional work to build on Windows.

Prequisites

Download the Adobe After Effects SDK.

⚠️ The SDK published by Adobe is outdated if you are using the 3D Artisan API to write your own 3D renderer plug-in. Also see Features below for more information.

Ignore this if you just want to develop 2D plugins (which still have access to 3D data).

Define the AESDK_ROOT environment variable that contains the path to your Ae SDK. Typically the directory structure will look like this:

AfterEffectsSDK
├── After_Effects_SDK_Guide.pdf
├── Examples
    ├── AEGP
    ├── Effect
    ├── ...

Features

  • artisan-2-api – Use the 2nd generation Artisan 3D API. This is not included in the official Ae SDK. Specifically it requires:

    • AE_Scene3D_Private.h
    • PR_Feature.h

    Contact the Adobe Ae SDK team and ask nicely and they may send you theses headers.

Using

Add after-effects to your dependencies.

cargo add after-effects

Getting Started

There are currently no examples. Use the C/C++ examples in the Ae SDK as guides for now. They translate more or less 1:1 to Rust when using this crate.

Help Wanted/To Do

  • Examples! I have a few plug-ins but they need polishing.

  • A build system extension that creates the bundle for Ae using cargo-post/cargo-make/cargo-bundle. I.e. enter one command to get a plug-in ready to load in Ae. Currently there are manual steps and they need documenting too.

  • Better error handling. Possibly using color-eyre?

License

Apache-2.0 OR BSD-3-Clause OR MIT OR Zlib at your option.

after-effects's People

Contributors

adrianeddy avatar dependabot-preview[bot] avatar dependabot[bot] avatar mobile-bungalow avatar virtualritz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

adrianeddy

after-effects's Issues

Dependabot can't resolve your Rust dependency files

Dependabot can't resolve your Rust dependency files.

As a result, Dependabot couldn't update your dependencies.

The error Dependabot encountered was:

    Updating crates.io index
error: no matching package named `aftereffects-sys` found
location searched: registry `https://github.com/rust-lang/crates.io-index`
required by package `aftereffects v0.1.0 (/home/dependabot/dependabot-updater/dependabot_tmp_dir

If you think the above is an error on Dependabot's side please don't hesitate to get in touch - we'll do whatever we can to fix it.

View the update logs.

Canonical naming

See the Rust API Guidelines on naming.

Just while going through #33, I saw a bunch of stuff that doesn't adhere to it.

For example, aeio::Handle is now aeio::AEIOHandle.

This is ugly for two reasons.

  1. Rust naming guidelines say aeio::AEIOHandle should rather be named aeio::AeIoHandle.

  2. However, consider std::io::Cursor. This is not named std::io::IoCursor.
    Or tokio::io::DumplexStream is not called tokio::io::IoDuplexStream.

    I.e. the module namespace is not repeated as a prefix on types in that module. This is not mentioned in the above document but kind of an unwritten rule, if you look at naming conventions used for structs in the std lib and common crates.

High level interface

I'm designing a high level plugin interface for the bindings, and my general idea is to have something like:

struct PortablePlugin { }
impl AdobePlugin for PortablePlugin {
    fn can_load(_host_name: &str, _host_version: &str) -> bool { true }
    fn new() -> Self { Self {} }

    fn handle_command(&mut self, cmd: Command) {
        match cmd {
            Command::About { mut out_data, .. } => {
                out_data.set_return_msg("Test plugin."));
            }
            Command::Render { in_data, mut params, output, .. } => {
                // ...
            }
            Command::GpuDeviceSetup { in_data, mut out_data, extra/*: GPUDeviceSetupExtra*/ } => { ... }
            // ...
        }
    }
}

register_plugin!(PortablePlugin);

basically the idea is to only expose relevant and valid data in each command, including all extras properly casted. I have that implemented so far, but I have a few concerns I wanted to discuss:

Struct instances

  1. Should we create and maintain global instance for user? What I imagine is that PortablePlugin struct would be stored in global_data and would be a single object alive for the entire time the project is open (and any plugin instance is added to the layer)
  2. Should we create and maintain sequence instance for user? That would be a separate struct, which is unique per every layer where the plugin is applied. This would be stored in sequence_data and I imagine I would require the user to make this struct serde::Serialize and serde::Deserialize and automatically handle flattening the data with bincode. Also that struct should be Send + Sync I believe, because AE can call the commands from any thread at any time? Is that correct?

I believe these two points are very useful for almost all plugins and at the same time quite time-consuming to implement properly by the user.
Pros:

  • User can focus on just his actual plugin code without worrying about complicated details of Handles and flattening
  • Much easier to get started with writing plugins

Cons:

  • A bit of memory overhead, since the instances would be always created. But since we're talking about video processing plugins here, any overhead like that is nothing compared to actual pixels processing so it should be fine. We could maybe make this optional with a register_plugin macro parameter or something

Parameters

  1. What do you think to create something like ParameterRegistry, which would be a manager for user params, with the enum-based getter/setter provided by user, and all parameters would be defined and retrieved using this enum. Something like:
enum MyParams {
    MixChannels
};
fn handle_command(&mut self, cmd: Command) {
    match cmd {
        Command::ParamsSetup { mut params } => {
            params.add_param(MyParams::MixChannels, 
                "Mix channels", 
                ae::FloatSliderDef::new()
                    .set_value(10.0)
                    .precision(1)
                    .display_flags(ae::ValueDisplayFlag::PERCENT)
            );
        }
        Command::Render { mut params, .. } => {
            let slider = params.get::<ae::Param::FloatSlider>(MyParams::MixChannels);
            // slider.value()
        }
    }
}
register_plugin!(PortablePlugin, MyParams);

That struct would maintain params array, indexes and counts (and would be stored in global instance data), so users won't have to worry about it.

I'll have more things to discuss once I get further, but let's start with these.

Let me know your thoughts, thanks!

CC @virtualritz @mobile-bungalow

PIPL Version

Just recording an undocumented tidbit from the Ae SDK list here:

The Pipl file effect version has to match PF_VERSION returned value otherwise you are limited to Max 7 for MAJOR_VERSION

    out_data->my_version = PF_VERSION(    MAJOR_VERSION,
                                        MINOR_VERSION,
                                        BUG_VERSION,
                                        STAGE_VERSION,
                                        BUILD_VERSION);    

Good thing to know for new plugins... as it has a limited purpose , plugin who currently somehow use VERSION defines for other things, can work around this with extra defines (locking MAJOR to 7 and shifting MAJOR to MINOR)...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.