Download

I cannot keep a reference alive, need advice.

Hi, so I am working on an alternative for the Pixel streaming feature of the engine, as a project. I have found a workaround for this issue but it is not ideal.

The ideal design is to store a reference to the FCapturedFrameData object (while keeping it alive) then letting slave threads do the parsing and encoding so the main thread does the absolute minimum. The code snippet below shows how I achieve this, but when I try to use the TSharedPtr to keep the reference to a rendered frame alive, it is garbage by the time a slave thread gets to it. My FrameProcessData structure is valid when being processed by the slave threads, except for the frame member that contains the TSharedPtr to the actual frame data which is garbage.

I think I may be using the shared pointers wrong, I’ve also exhausted other methods of manual referencing, except for storing the reference in the class itself.

my current working solution is to let the main thread parse the rendered frame data on line 108.


void AStreamActor::CaptureFrame(void)
{
    FFramePayloadPtr pl;
    this->captureObj->CaptureThisFrame(pl);
    TArray<FCapturedFrameData> frames = this->captureObj->GetCapturedFrames();
    UINT l = frames.Num();
    UE_LOG(LogTemp, Warning, TEXT("Captured frames: %d."), l);
    if (l > 0) {
        FCapturedFrameData &frame = frames[l - 1];
        FrameProcessData* p = new(std::nothrow) FrameProcessData();
        /*FrameProcessData d(this->frameCounter, false, 0, 0, 0, nullptr, nullptr);
        if (this->FrameMap == nullptr || this->frameQueue == nullptr) {
            UE_LOG(LogTemp, Warning, TEXT("*Frame Queue or Frame Map is null."));
            return;
        }
        d.width = frame.BufferSize.X;
        d.height = frame.BufferSize.Y;
        d.frame = MakeShared<FCapturedFrameData*>(&frame);*/
        p->height = frame.BufferSize.Y;
        p->width = frame.BufferSize.X;
        p->frame = MakeShared<FCapturedFrameData*, ESPMode::ThreadSafe>(&frame);
        UE_LOG(LogTemp, Warning, TEXT("reference count[0]: %d."), p->frame.GetSharedReferenceCount());
        p->encoder = nullptr;
        p->isReady = false;
        //TSharedPtr<FrameProcessData*> ptr = MakeShared<FrameProcessData*>(&d);
Line 108: p->arrRGB = ((ARenderStreamGameModeBase*)gameMode)->ConvertFrame(frame.ColorBuffer, p->arrLen);
        this->FrameMap->Add(this->frameCounter, p);
        this->frameQueue->Enqueue(this->frameCounter);
        this->frameCounter++;
        UE_LOG(LogTemp, Warning, TEXT("memory colours: %d|%d|%d."), frame.ColorBuffer.Last().R, frame.ColorBuffer.Last().G, frame.ColorBuffer.Last().B);
        UE_LOG(LogTemp, Warning, TEXT("memory colours: %d|%d|%d."), p->arrRGB[p->arrLen - 3], p->arrRGB[p->arrLen - 2], p->arrRGB[p->arrLen - 1]);
        /*int x = 0;
        char* ptr = this->ParseFrameFAST(&frame, x, 1);
        delete] ptr;*/
        //UE_LOG(LogTemp, Warning, TEXT("Frame saved: %d."), p->width*p->height);
    }
}

A rendered frame from ideal design:

Also here is a rendered frame after my hotfix: