Copy link to clipboard
Copied
Long shot, and obviously don't expect any hyper-specific answers, but I was wondering if anyone might have some insight on how extendscript.dll, scripting.aex, and CEPManager.aex work together?
When doing some debugging, I notice that when extendscript is called, it loads both scripting.aex, and extendscript.dll.
Same with CEPManager.aex.
My assumption is that scripting.aex loads extendscript.dll, and performs script execution.
CEPManager.aex would probably do similar.
This being said, how exactly might all of this work together?
I'm working on a plugin that exposes python as an alternative, and I'm running into some issues when figuring out how to run concurrent scripts.
I've embedded a python module that wraps SDK calls, and have successfully created a python API as a (partial) alternative to extendscript. I can successfuly call into the plugin with a python script, which will then perform automations (making new project, comp, manipulating layers, etc).
However, I can only have one embedded python instance per process.
Since loading a new process gives a different address space, the embedded module is no longer available.
For example, I have the following class set up in c++.
```c++
//Project class definition
class Project {
public:
Project() = default; // Default constructor
explicit Project(const Result<AEGP_ItemH>& itemHandle)
: activeItem(std::make_shared<Item>(itemHandle)) {}
std::shared_ptr<Item> ActiveItem();
std::shared_ptr<Layer> GetActiveLayer();
std::string getName();
std::string getPath();
void saveAs(std::string path);
std::shared_ptr<ProjectCollection> ChildItems();
std::shared_ptr<ProjectCollection> SelectedItems();
private:
std::shared_ptr<Item> activeItem;
Result<AEGP_ProjectH> projH_;
};
```
It calls into the main AE thread through a messagequeue managed through mutexes.
This same class is exposed to python like so;
```
py::class_<Project, std::shared_ptr<Project>>(m, "Project")
.def(py::init<>())
.def_property_readonly("activeItem", &Project::ActiveItem, py::return_value_policy::reference)
.def_property_readonly("activeLayer", &Project::GetActiveLayer, py::return_value_policy::reference)
.def_property_readonly("name", &Project::getName)
.def_property_readonly("path", &Project::getPath)
.def_property_readonly("items", &Project::ChildItems, py::return_value_policy::reference)
.def_property_readonly("selectedItems", &Project::SelectedItems, py::return_value_policy::reference)
.def("saveAs", &Project::saveAs, py::arg("path"));
```
I don't think I can pass things like AEGP_ProjectH across processes without invalidating the original, so that being said, I think my only option would be refactoring the python bindings into a separate, importable library, but the problem here lies in how would I communicate complex classes and such between these processes?
I'm hoping that some insight into how the extendscript communication works might help out, or any other suggestions would be GREATLY appreciated. Thank you!!!
Copy link to clipboard
Copied
well... i don't know how these components work together, but i have a few thoughts in regards to all you've written here.
since in AE there are separate threads for rendering, and one thread for ui, each of these separate threads is independent of the others. render threads are, of course, forbidden from changing the project, and are only good for rendering puposes (or sending analytics over to the ui thread).
the only thread allowed to change the project is the UI thead.
having said that, what are the concurrent scripts you're running? if they're render scripts, then there shouldn't be a problem operating in parallel. if they're "project manipulation" scripts, why are they concurrent?
having asked that, i'll continue assuming you have your good reasons.
as for having multiple python instances per process. if i understand you correctly, you mean by "process" you mean "ae program instance"? meaning, you're talking about 1 ae process talking to multiple python processes, right? and not, say, multiple instances of ae are open with the same project and you wish to use data from one as valid on the other...
i'll assume you're not INSANE and go with the former assumption...
so, i see no problem transfering ae stuff like an AEGP_ItemH between python processes, as all of these objects are references to some opaque data struct ae owns, so the reference remains valid and there no memory owned by one process travelling to the other.
the thing to consider, though, is the lifespan of each of these items. officially, you shouldn't trust these objects beyond the scope of a single AE call. (i.e, from the beginnig of an idle_hook or render call, until that call returns to ae)
some of these items invalide immediatly, some seem to stick around. i've used an AEGP_ItemH over the span of a whole AE session, and it remained valid. AEGP_LayerH seems persistant over the session as well. AEGP_EffectRefH on the other hand, explodes as soon as the call is done...
i'm not saying some items are guaranteed to stay valid throughout a session, as the docs don't mention it, but that's my experience with them.
so how does that concerns your development? i don't know the life span of your scripts. which means:
1. if a script is born and dies within the same AE call, all items aquired by it are valid thoughout it's lifespan. if it sticks around across AE calls, some item types may invalide in between.
2. if one script passes an item to another, and the other script lives beyond the scope of the first script's launching AE call, some of the passed items will have invalidated between AE calls.
3. items need to be disposed of. meaning, if a script passede an item onto another, then the first script exits and disposes of the checkout items it had, the passed ones will become invalid. again, these items are references to some internal AE data. it's not a copy of the data itself.
4. scripts may do contradictory things, so one script may try to act on an item already invalidated by another. for example, one script may try to access some layer it has a handle to, after a concurrent script had deleted it.
so i didn't answer your original question, but i hope my thoughts here can help.
and oh, BTW, are you familiar with ExtendScript external objects?
take a peek at "C:\Program Files (x86)\Adobe\Adobe Utilities - CS6\ExtendScript Toolkit CS6\SDK\Samples\cpp".
you can create a c++ plug-in that adds capabilities to AE's javascript. when your functions are called, it invokes the c++ plugin along with the call data, the plugin does on the c++ side whatever it wants, and returns the result back to javascript.
i don't know how that plays into your work scheme, but maybe it will spark your imagination... say, run python code from within a regualr AE script 🙂
Copy link to clipboard
Copied
Hey Shachar! Great to see you here again! 🙂
I'll try to answer everything in the order it was presented--
Scripts vary, quite broadly. Put simply, my plugin offers python as a full alternative to extendscript, so any manipulation you can do in ES, you can do with my plugin, and then some. Conccurency may or may not occur, as in the case of running multiple CEP, which call into the single threaded extendscript.
Hahaha, yes! I feel quite insane sometimes, but I'm not THAT insane! Single AE process, multiple interpreters.
I've had similar experiences. Most of the standard types seem to persist throughout sessions, which is extremely lucky for my usage.
Your thoughts have certainly helped, and theres definitely some more gears turning now.
I think my current best thought is going with a gRPC /protocol buffer service, that way I can have multiple interpreters running, and still execute main thread AE functions.
I have looked into External Objects and played around a bit, but ultimately by goal is to keep up to date with the SDK, and create a future proof scripting language. (I know UXP is coming, but still).
I think out of any Adobe Product, AE has the best potential for python integration-- Data Driven animations, machine learning integration, etc!
Copy link to clipboard
Copied
ah! now that you've mentioned multiple CEP being open at the same time, i see what you mean by concurrency.
in that regard, i do know a bit about what's going on there behind the scence.
the calls from the CEP panel to AE's extendscript API are actually async. the result of the call comes around at a later time, and not synchronously with the call.
the layer between the CEP and AE's extendscript is called "vulcan", and it's responsible for handling these async requests, queueing them, talking to AE at the appropriate time, and returning the results.
part of the premise of and motivation behind UPX, is ridding of the vulcan layer and making the communication with AE synchronous.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now