Copy link to clipboard
Copied
class AsyncRenderManager
{
public:
AsyncRenderManager() {}
// Method to initiate async rendering with an optional custom callback
void renderAsync(LayerRenderOptionsPtr optionsH, std::function<void(WorldPtr)> callbackF)
{
auto callbackPtr = new std::function<void(WorldPtr)>(callbackF);
auto ret = std::async(std::launch::async, [optionsH, callbackPtr]() {
RenderSuite().renderAndCheckoutLayerFrameAsync(optionsH, callback,
reinterpret_cast<AEGP_AsyncFrameRequestRefcon>(callbackPtr));
});
}
// Existing static callback method remains unchanged
static A_Err callback(AEGP_AsyncRequestId request_id, A_Boolean was_canceled, A_Err error,
AEGP_FrameReceiptH receiptH, AEGP_AsyncFrameRequestRefcon refconP0)
{
auto callbackPtr = reinterpret_cast<std::function<void(WorldPtr)> *>(refconP0);
if (callbackPtr && *callbackPtr)
{
FrameReceiptPtr ptr = std::make_shared<AEGP_FrameReceiptH>(receiptH);
auto world = RenderSuite().getReceiptWorld(ptr);
(*callbackPtr)(world);
delete callbackPtr;
}
return error;
}
};
And my version of Grabba:
void saveFrame(int i, LayerRenderOptionsPtr layerRenderOptions) {
LayerRenderOptionsSuite().setTime(layerRenderOptions, FramesToTime(i)); // Set the time of the layer render options
AsyncRenderManager rmanager; // Create an instance of the AsyncRenderManager class
rmanager.renderAsync(layerRenderOptions, [i](WorldPtr world) { // Call the renderAsync method with a lambda function
if (world) {
std::string folder = "C:\\Users\\tjerf\\Downloads\\pdf_output\\New folder\\";
auto data = Image::data(world); // Get the image data from the world
Image::saveImage(folder + "\\frame" + std::to_string(i) + ".png", "png", data); // Save the image to disk
}
});
}
void GrabbaCommand::execute() {
try {
auto layer = Layer::activeLayer(); // Get the active layer
auto duration = layer->duration(); // Get the duration of the layer
auto framerate = layer->parentComp()->frameRate(); // Get the frame rate of the composition
int numframes = static_cast<int>(std::round(duration * framerate)); // Calculate the number of frames
auto layerRenderOptions = LayerRenderOptionsSuite().newFromLayer(layer->getLayer()); // Create a new LayerRenderOptions object
// Prepare a vector of futures to hold the results of async operations
std::vector<std::future<void>> futures;
for (int i = 0; i < numframes; ++i) { // Loop through each frame
// Capture 'i' by value to ensure each thread gets the correct frame number
auto future = std::async(std::launch::async, [i, &layerRenderOptions]() {
saveFrame(i, layerRenderOptions);
});
futures.push_back(std::move(future)); // Move the future into the vector
}
// Wait for all async operations to complete
for (auto& future : futures) {
future.wait(); // Wait for the future to complete
}
}
catch (const std::exception& e) {
App::Alert(e.what()); // Display the exception message
}
catch (...) {
App::Alert("An unknown error occurred.");
}
}
actually, this issue has recently been dicussed between several devs and the AE team. apprently, there's a problem with the memory realsing when using the async version of renderAndCheckout. all devs reverted back to the synchronous version, and just do their best to render a frame at a time on each idle cycle as not to make the ui laggy...
Copy link to clipboard
Copied
actually, this issue has recently been dicussed between several devs and the AE team. apprently, there's a problem with the memory realsing when using the async version of renderAndCheckout. all devs reverted back to the synchronous version, and just do their best to render a frame at a time on each idle cycle as not to make the ui laggy...
Copy link to clipboard
Copied
Ahhh, thank you!
That explains a lot. I noticed checking in the frame receipt wasn't possible-- I figured that was just because you weren't supposed to, but there being a bug makes more sense!