Copy link to clipboard
Copied
Hi,
I'm new to the After Effects sdk. I've set the out_data->out_flags to include PF_OutFlag_REFRESH_UI and PF_OutFlag_FORCE_RERENDER in the PF_Cmd_USER_CHANGED_PARAM handler. This works correctly when the parameter value is changed within the user interface.
I recently integrated WebSocket using easywsclient to receive messages from an external application, and I'm handling the messages in a separate thread using tinythread, which is from easywsclient.
Whenever I want to force render on a button tap or anywhere, I set the out_data->out_flags with PF_OutFlag_REFRESH_UI andPF_OutFlag_FORCE_RERENDER.
But if I set these out_flags in the separate thread in which I'm handling the messages received from the websocket, the UI isn't force rendered.
Is there a way to come back to the main UI thread or call a function in the main thraed when receiving message in the other thread?
Or another way to force render when I receive a message in the separate thread.
Thank you!
it's possible only via idle hook. wait for an idle event (happens 30-50 times per second), check your other thread for messages and act. idle calls happen on the UI thread, so it's a valid time to make changes to the project.
you can either:
1. change some invisible param value that would force a re-render.
2. call the command number to purge the cache.
3. call AEGP_EffectCallGeneric and have the effect instance act on itself.
anything happening on a separate thread can be synced back to the main thread only during main thread events. for rapid updating, idle_hook is the best way to go.
AEGP_EffectCallGeneric won't help in that regard, as it can't change the project from render threads, and can only operate during main thread events. it only helps if you want the effect to operate on itself in ways not accessible via external effect. for example, accessing the sequence data.
add some hidden param, and change it's value when you can to force a re-render in idle_hook.
Copy link to clipboard
Copied
it's possible only via idle hook. wait for an idle event (happens 30-50 times per second), check your other thread for messages and act. idle calls happen on the UI thread, so it's a valid time to make changes to the project.
you can either:
1. change some invisible param value that would force a re-render.
2. call the command number to purge the cache.
3. call AEGP_EffectCallGeneric and have the effect instance act on itself.
Copy link to clipboard
Copied
1. I tried changing an invisible param value, which does force a re-render, but not in a separate thread. Is there a right way to change the param value in the main UI thread?
2. If I call the commands 2372 or 2373, it usually doesn't cause the re-render (although sometimes it does). If I call the command 10200, it does force a render but it gives me a popup "Are you sure you want to delete caches". And I don't want a popup to be there everytime.
3. I tried to find about the AEGP_EffectCallGeneric but not sure how it can help me
Copy link to clipboard
Copied
anything happening on a separate thread can be synced back to the main thread only during main thread events. for rapid updating, idle_hook is the best way to go.
AEGP_EffectCallGeneric won't help in that regard, as it can't change the project from render threads, and can only operate during main thread events. it only helps if you want the effect to operate on itself in ways not accessible via external effect. for example, accessing the sequence data.
Copy link to clipboard
Copied
If I try to force render in an Idle hook, how will I get out_data, to call the
out_data->out_flags |= PF_OutFlag_REFRESH_UI | PF_OutFlag_FORCE_RERENDER
Storing the out_data as global however doesn't work
I had another workaround in mind. Can I add a command in Edit menu to force a rerender? And when in the other thread I want to re-render, I can call the command with the DO_Command. But the problem is again that I don't have the out_data for which to call force render and refreshUI
Copy link to clipboard
Copied
add some hidden param, and change it's value when you can to force a re-render in idle_hook.
Copy link to clipboard
Copied
Thanks for your time Shachar, but even IdleHook doesn't work for me.
All the print logs I add in IdleHook, they show up. But when my value is updated, param is not actually updating in the UI, neither render is called.
If i add a button and update the param on buton click, it works.
Copy link to clipboard
Copied
Nvm, This answer of yours helped me to achieve it. https://community.adobe.com/t5/after-effects-discussions/using-aegp-startundogroup-endundo-to-force-...
I had been trying to setup the idlehook in global setup, but setting up in sequence setup worked for me.
Copy link to clipboard
Copied
hmmm... interesting...
sequcnce_setup is called only once per *new* instance of the effect. meaning, it's called when the user creates a new instance via selecting the effect from the effect's menu. copy/pasted or duplicated instances don't get a sequence_setup call, but rather a sequence_resetup call, and so do existing instances when a project is loaded.
if your desing is that there should be one idle_hook for all instances together, then global setup is the place to set it up on. if you're aiming for an idle_hook PER instance, then sequence_setup doesn't guarntee that.
what is the problem with setting it up during global setup? that's where i implement idle hook on effect plugins.
Copy link to clipboard
Copied
If I set it up in the GlobalSetup, there is an error popup which says 'Effect cannot be initialized'
Copy link to clipboard
Copied
so probably some error code is generated by AE from one of the callbacks, which in turn is returned to AE from the global setup call. an error during global setup would indeed cause the plugin to not work.
what line causes the problem? what is the error returned?
Copy link to clipboard
Copied
Sorry for the misunderstanding, that was not the error.
The error was "Internal structure inconsistency 25:227"
which I get when I try to call AEGP_GetEffectLayer, not while registring commandHook
Copy link to clipboard
Copied
ah, yes. makes sense. there is no effect isntance at the time of global_setup, so there's no way to get an effect ref.
Copy link to clipboard
Copied
I had another concern. If I have a param of type double with value 0. In the IdleHook, I updated the value to 5, Render will be called. Now next time when I want to force a rerender, I again update the param value to 0, it stores the last instance and doesn't call render for new data
Copy link to clipboard
Copied
yeah, either incremet, or put some random value, like the time stamp or simething unlikely to ever repeat.
Copy link to clipboard
Copied
Ok currently I'm incrementing. But my param is a slider type, which will have a max value. Is there a param that can have infinite values?
Copy link to clipboard
Copied
well, maybe an arb param, bu that's a bit of an overkill.
i'd go with a timestamp. the chances of hitting 2 equal values that happen to be cached are negligible.
Copy link to clipboard
Copied
Can I add a timeStamp param in the paramsSetup?
Copy link to clipboard
Copied
Yes, but param setup happens only once per session and applies to all instnances created in that session, so they would all have the same value.
Copy link to clipboard
Copied
Hey,
Thanks for all your answers
I found this in the AE_GeneralPlug.h, which makes me doubt updating an arb param in the SetStreamValue. It says it is illegal on AEGP_ArbBlockVal. Not sure if it is written for AEGP_SetStreamValue or AEGP_GetLayerStreamValue.
SPAPI A_Err (*AEGP_SetStreamValue)( // only legal to call when AEGP_GetStreamNumKFs==0 or NO_DATA
AEGP_PluginIDaegp_plugin_id,/* >> */
AEGP_StreamRefH streamH,/* >> */
AEGP_StreamValue2*valueP);/* << */
// this is only valid on streams with primitive types. It is illegal on
// AEGP_ArbBlockVal || AEGP_MarkerValP || AEGP_MaskOutlineValH
SPAPI A_Err (*AEGP_GetLayerStreamValue)(
AEGP_LayerHlayerH,/* >> */
AEGP_LayerStreamwhich_stream,/* >> */
AEGP_LTimeModetime_mode,/* >> */
const A_Time *timePT, /* >> */
A_Boolean pre_expressionB, /* >> sample the stream before evaluating the expression */
AEGP_StreamVal2*stream_valP,/* << */
AEGP_StreamType *stream_typeP0);/* << */
Copy link to clipboard
Copied
then use AEGP_GetNewStreamValue.