• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Help with AEGP_RenderAndCheckOutLayerFrame_Async?

Explorer ,
Apr 12, 2024 Apr 12, 2024

Copy link to clipboard

Copied

I've been experimenting with AEGP_RenderAndCheckoutLayerFrame_Async lately, and came across some interesting behavior.
I believe further experimentation could result in some pretty interesting usage from within AEGPs.

Starting with my version of the `Grabba` sample project, I created an AsyncManager class to handle calling AEGP_RenderAndCheckoutLayerFrame_Async.

Couple of interesting tidbits I've noticed:
- This call IS safe to use on other threads, as long as only one thread is calling it at a time.
- The Callback Function comes from `BEE.dll`, and works with (I haven't tried all, but I'd assume) all standard AEGP calls.


Main pain points/questions-
I'm looking for recommendations on capturing and safely returning the AEGP_WorldH (referred to as WorldPtr in my library) back to the main thread from the callback function. Currently,
I've tried captureing by reference in the lambda and directly returning as a future, but I'm seeing some memory issues in doing so ( I believe corruption related).
 Has anyone dealt with similar challenges?

- In its current state, things work out properly-- From an AEGP Plugin, I can render 96 [1920x1080] frames, async, in 0.06s.
    - This being said, I could totally see this expanding into AEGP's being able to do more "effect-like" processing.

Here's the classes being used for reference;

AsyncManager:
 

 

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.");
    }
}

 



TOPICS
Crash , Error or problem , Freeze or hang , How to , SDK

Views

214

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Apr 12, 2024 Apr 12, 2024

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...

Votes

Translate

Translate
Community Expert ,
Apr 12, 2024 Apr 12, 2024

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...

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Apr 13, 2024 Apr 13, 2024

Copy link to clipboard

Copied

LATEST

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!


Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines