Struggling to understand extent_hint and image buffer
- July 2, 2025
- 1 reply
- 384 views
I am currently creating an Premiere Pro plugin using the After Effects C++ SDK. I created a simple Tinter plugin that tints all pixels in my clip. To iterate on all of the pixels, I am using the iterate function.
My problem
The plugin worked well, but when I applied it to a clip that had a smaller resolution (1920 x 1080) than my
sequence global resolution (3840 x 2160), I realized that the effect was applied to all the sequence's pixels, and not just my clip's pixels. I don't understand why, since I didn't neither manipulate the output size nor used the PF_OutFlag_I_EXPAND_BUFFER flag.
What I have checked so far
Using breakpoints and the debugger, I verified that no variable (in_data, out_data, output, all of the extent_hint variables) was containing informations about the sequence resolution. The only time where the sequence resolution was visible was within the iterate function, when looking at the x and y coordinates, but I have no idea as up to where it comes from...
I tried to manipulate the area parameter of the iterate function, but none of the followings solved my issue :
- Using NULL
- Using ¶ms[PLUGIN_INPUT]->u.ld.extent_hint
- Using &output->extent_hint
I have found a workaround by looking at Nate's pixel by pixel control video, but this is just ignoring the transparent pixels. It does not prevent the effect from iterating over the entire sequence, which seems like a massive performance issue, aspecially for 4K resolution scenes...
I tried to force a value to the output buffer size in the FrameSetup sequence, like you would normally do if you wanted to expand the buffer, but that didn't work as well...
Any help would be greatly appreciated !
My code
#include "plugin.h"
static PF_Err
About (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
AEGP_SuiteHandler suites(in_data->pica_basicP);
suites.ANSICallbacksSuite1()->sprintf( out_data->return_msg,
"%s v%d.%d\r%s",
STR(StrID_Name),
MAJOR_VERSION,
MINOR_VERSION,
STR(StrID_Description));
return PF_Err_NONE;
}
static PF_Err
GlobalSetup (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
out_data->my_version = PF_VERSION( MAJOR_VERSION,
MINOR_VERSION,
BUG_VERSION,
STAGE_VERSION,
BUILD_VERSION);
out_data->out_flags = PF_OutFlag_DEEP_COLOR_AWARE ; // just 16bpc, not 32bpc
return PF_Err_NONE;
}
static PF_Err
FrameSetup (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
// out_data->width = in_data->width;
// out_data-> height = in_data->height;
// output->extent_hint = params[PLUGIN_INPUT]->u.ld.extent_hint;
return PF_Err_NONE;
}
static PF_Err
ParamsSetup (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
PF_ParamDef def;
AEFX_CLR_STRUCT(def);
PF_ADD_FLOAT_SLIDERX(
STR(StrID_Ratio_Param_Name),
TINTER_RATIO_MIN,
TINTER_RATIO_MAX,
TINTER_RATIO_MIN,
TINTER_RATIO_MAX,
TINTER_RATIO_DFLT,
PF_Precision_TENTHS,
0,
0,
RATIO_DISK_ID);
AEFX_CLR_STRUCT(def);
PF_ADD_COLOR(
STR(StrID_Color_Param_Name),
128,
255,
255,
COLOR_DISK_ID
);
AEFX_CLR_STRUCT(def);
out_data->num_params = PLUGIN_NUM_PARAMS;
return err;
}
PF_Err TintImage8(void *refcon, A_long x, A_long y, PF_Pixel *inPixel, PF_Pixel *outPixel) {
if (inPixel->alpha == 0) {
return PF_Err_NONE;
}
SettingsInfo* effectSettings = (SettingsInfo*)refcon;
*outPixel = *inPixel;
plugin::tint::tint_pixel(
*(reinterpret_cast<plugin::tint::rgba_pixel*>(&effectSettings->color)),
reinterpret_cast<plugin::tint::rgba_pixel*>(outPixel),
effectSettings->ratio
);
return PF_Err_NONE;
}
static PF_Err
Render (
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output )
{
PF_Err err = PF_Err_NONE;
SettingsInfo effectSettings;
AEFX_CLR_STRUCT(effectSettings);
effectSettings.color = params[TINTER_COLOR]->u.cd.value;
effectSettings.ratio = static_cast<float>(params[TINTER_RATIO]->u.fs_d.value / 100);
const int lines = output->extent_hint.bottom - output->extent_hint.top;
AEGP_SuiteHandler suites(in_data->pica_basicP);
ERR(suites.Iterate8Suite2()->iterate(
in_data,
0,
lines,
¶ms[PLUGIN_INPUT]->u.ld,
&output->extent_hint,
(void *)&effectSettings,
TintImage8,
output
));
return err;
}
extern "C" DllExport
PF_Err PluginDataEntryFunction2(
PF_PluginDataPtr inPtr,
PF_PluginDataCB2 inPluginDataCallBackPtr,
SPBasicSuite* inSPBasicSuitePtr,
const char* inHostName,
const char* inHostVersion)
{
PF_Err result = PF_Err_INVALID_CALLBACK;
result = PF_REGISTER_EFFECT_EXT2(
inPtr,
inPluginDataCallBackPtr,
"Tinter", // Name
"ADBE Tinter", // Match Name
"Anatole", // Category
AE_RESERVED_INFO, // Reserved Info
"EffectMain", // Entry point
"https://www.adobe.com"); // support URL
return result;
}
PF_Err
EffectMain(
PF_Cmd cmd,
PF_InData *in_data,
PF_OutData *out_data,
PF_ParamDef *params[],
PF_LayerDef *output,
void *extra)
{
PF_Err err = PF_Err_NONE;
try {
switch (cmd) {
case PF_Cmd_ABOUT:
err = About(in_data,
out_data,
params,
output);
break;
case PF_Cmd_GLOBAL_SETUP:
err = GlobalSetup( in_data,
out_data,
params,
output);
break;
case PF_Cmd_PARAMS_SETUP:
err = ParamsSetup( in_data,
out_data,
params,
output);
break;
case PF_Cmd_FRAME_SETUP:
err = FrameSetup( in_data,
out_data,
params,
output);
break;
case PF_Cmd_RENDER:
err = Render( in_data,
out_data,
params,
output);
break;
}
}
catch(PF_Err &thrown_err){
err = thrown_err;
}
return err;
}
