c++videomemory-managementms-media-foundationscreen-capture

How to reuse an IMFSample without consuming additional memory


I wrote a screen video capture program in C++ /CLI. I capture the video 30 times a second and display it in a picture box. My idea was to copy the IMFSample to a reusable output sample then free the source sample to control memory usage.

Although I call sampleOut->RemoveAllBuffers() prior to sampleOut->AddBuffer(destBuf), it still consumes additional memory. It appears that RemoveAllBuffers doesn't actually free the memory from the prior video frame. Any idea how I can free the memory without having to release the sampleOut and recreate it?

HRESULT ScreenCapture::DuplicateSample(IMFSample* sample)
{       
    HRESULT hr = S_OK;

    if (!sample)
    {
        hr = E_ABORT;
        return hr;
    }
            
    DWORD sampleFlags = 0;
    LONGLONG llVideoTimeStamp = 0;
    LONGLONG llSampleDuration = 0;
    IMFMediaBuffer* srcBuf;
    IMFMediaBuffer* destBuf;

    hr = sample->GetSampleFlags(&sampleFlags);
    hr = sample->GetSampleTime(&llVideoTimeStamp);
    hr = sample->GetSampleDuration(&llSampleDuration);

    hr = sampleOut->SetSampleFlags(sampleFlags);
    hr = sampleOut->SetSampleTime(llVideoTimeStamp);
    hr = sampleOut->SetSampleDuration(llSampleDuration);

    srcBuf = nullptr;
    hr = sample->GetBufferByIndex(0, &srcBuf);

    byte* srcByteBuffer = nullptr;
    DWORD srcBuffCurrLen = 0;
    DWORD srcBuffMaxLen = 0;

    hr = srcBuf->Lock(&srcByteBuffer, &srcBuffMaxLen, &srcBuffCurrLen);

    destBuf = nullptr;
    hr = MFCreateMemoryBuffer(srcBuffCurrLen, &destBuf);

    byte* destByteBuffer = nullptr;

    hr = destBuf->Lock(&destByteBuffer, nullptr, nullptr);

    memcpy(destByteBuffer, srcByteBuffer, srcBuffCurrLen);

    hr = destBuf->Unlock();
    hr = srcBuf->Unlock();

    hr = destBuf->SetCurrentLength(srcBuffCurrLen);

    SafeRelease(&srcBuf);

    sampleOut->RemoveAllBuffers();
    hr = sampleOut->AddBuffer(destBuf); //Memory issue here

    SafeRelease(&destBuf);

    return hr;
}

As you can see I also need a better way to handle the hr testing for each step. I figured I deal with that after I get the code working.

Thanks for your help!


Solution

  • The question you are interested in is how to reuse samples instead of allocating them each time. The primary call you want to avoid is MFCreateMemoryBuffer because it is the actual memory consumer, not the buffer attachment/detachment from sample objects.

    The ideal solution is along these lines:

    This is exactly how allocators provided by mentioned MFCreateVideoSampleAllocatorEx work.